
I'm currently updating some of my code to take advantage of C++0x features where available, but I also want to retain backwards compatibility with C++03. I was looking at scoped enums and noticed a thread on the mailing list by Beman Dawes discussing a scoped enum emulation implementation for Boost. I see that it's currently being used by Boost, and resides in /boost/detail/scoped_enum_emulation.hpp. My question is, why is this an implementation detail? Would it be possible for it to be moved to Boost.Config with the other 'helper' macros like BOOST_CONSTEXPR? Obviously it's not hard to reimplement, but I figured that it would be useful to other library users, so it would be best (imo) if it were moved somewhere public, rather than being hidden away. Thanks.

On Tue, Jan 24, 2012 at 12:06 PM, Joshua Boyce <raptorfactor@raptorfactor.com> wrote:
I'm currently updating some of my code to take advantage of C++0x features where available, but I also want to retain backwards compatibility with C++03. I was looking at scoped enums and noticed a thread on the mailing list by Beman Dawes discussing a scoped enum emulation implementation for Boost. I see that it's currently being used by Boost, and resides in /boost/detail/scoped_enum_emulation.hpp.
My question is, why is this an implementation detail? Would it be possible for it to be moved to Boost.Config with the other 'helper' macros like BOOST_CONSTEXPR?
Obviously it's not hard to reimplement, but I figured that it would be useful to other library users, so it would be best (imo) if it were moved somewhere public, rather than being hidden away.
It isn't a full emulation of C++11's scoped enum feature. That's probably why it ended up in detail rather than config, although I've forgotten the detailed rationale, if there ever was any. What do others think? Should /boost/detail/scoped_enum_emulation.hpp functionality be moved to config? Are there any improvements that would make the emulation better, without turning something simple into something complex? --Beman

Le 24/01/12 22:51, Beman Dawes a écrit :
I'm currently updating some of my code to take advantage of C++0x features where available, but I also want to retain backwards compatibility with C++03. I was looking at scoped enums and noticed a thread on the mailing list by Beman Dawes discussing a scoped enum emulation implementation for Boost. I see that it's currently being used by Boost, and resides in /boost/detail/scoped_enum_emulation.hpp.
My question is, why is this an implementation detail? Would it be possible for it to be moved to Boost.Config with the other 'helper' macros like BOOST_CONSTEXPR?
Obviously it's not hard to reimplement, but I figured that it would be useful to other library users, so it would be best (imo) if it were moved somewhere public, rather than being hidden away. It isn't a full emulation of C++11's scoped enum feature. That's
On Tue, Jan 24, 2012 at 12:06 PM, Joshua Boyce <raptorfactor@raptorfactor.com> wrote: probably why it ended up in detail rather than config, although I've forgotten the detailed rationale, if there ever was any.
What do others think? Should /boost/detail/scoped_enum_emulation.hpp functionality be moved to config?
Are there any improvements that would make the emulation better, without turning something simple into something complex?
Hi, I'm working with a different emulation which uses classes. For example // enum class cv_status; BOOST_DECLARE_STRONG_ENUM_BEGIN(cv_status) { no_timeout, timeout }; BOOST_DECLARE_STRONG_ENUM_END(cv_status) The macros are defined as follows: #ifdef BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) \ struct x { \ enum enum_type #define BOOST_DECLARE_STRONG_ENUM_END(x) \ enum_type v_; \ inline x() {} \ inline x(enum_type v) : v_(v) {} \ inline operator int() const {return v_;} \ friend inline bool operator ==(x lhs, int rhs) {return lhs.v_==rhs;} \ friend inline bool operator ==(int lhs, x rhs) {return lhs==rhs.v_;} \ friend inline bool operator !=(x lhs, int rhs) {return lhs.v_!=rhs;} \ friend inline bool operator !=(int lhs, x rhs) {return lhs!=rhs.v_;} \ }; #define BOOST_STRONG_ENUM_NATIVE(x) x::enum_type #else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS While this is not yet a complete emulation of scoped enums, it has the advantage of that there is no need to use a macro to name the strong type. I don't know if it will be confusing to put provide both approaches in a single mini library. Best, Vicente

On Wed, Jan 25, 2012 at 9:17 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Hi,
I'm working with a different emulation which uses classes. For example
<CODE SNIPPED>
While this is not yet a complete emulation of scoped enums, it has the advantage of that there is no need to use a macro to name the strong type.
I don't know if it will be confusing to put provide both approaches in a single mini library.
Best, Vicente
Out of curiosity, what are the cons of this implementation compared to the existing one? (The pros seem fairly obvious, but I think I'm missing the downside...)

Le 25/01/12 02:40, Joshua Boyce a écrit :
On Wed, Jan 25, 2012 at 9:17 AM, Vicente J. Botet Escriba< vicente.botet@wanadoo.fr> wrote:
While this is not yet a complete emulation of scoped enums, it has the advantage of that there is no need to use a macro to name the strong type.
I don't know if it will be confusing to put provide both approaches in a single mini library.
Best, Vicente
Out of curiosity, what are the cons of this implementation compared to the existing one? (The pros seem fairly obvious, but I think I'm missing the downside...)
Respect to the Beman approach, the major downside I can see is that a strong enum is not always and enumeration, so cannot be used in a portable way where an enum is expected (e.g. switch, ...). Something else is needed to be able to write portable code. In addition, not all c++ compilers provide explicit conversion, so either we need to use a explicit function to convert to the underlying type or let the underlying type conversion operator implicit. Best, Vicente

Vicente J. Botet wrote:
Le 24/01/12 22:51, Beman Dawes a écrit :
What do others think? Should
/boost/detail/scoped_enum_emulation.hpp
functionality be moved to config?
Are there any improvements that would make the emulation better, without turning something simple into something complex?
I'm working with a different emulation which uses classes. For example
// enum class cv_status; BOOST_DECLARE_STRONG_ENUM_BEGIN(cv_status) { no_timeout, timeout }; BOOST_DECLARE_STRONG_ENUM_END(cv_status)
The macros are defined as follows:
#ifdef BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) \ struct x { \ enum enum_type
#define BOOST_DECLARE_STRONG_ENUM_END(x) \ enum_type v_; \ inline x() {} \ inline x(enum_type v) : v_(v) {} \ inline operator int() const {return v_;} \ friend inline bool operator ==(x lhs, int rhs) \ {return lhs.v_==rhs;} \ friend inline bool operator ==(int lhs, x rhs) \ {return lhs==rhs.v_;} \ friend inline bool operator !=(x lhs, int rhs) \ {return lhs.v_!=rhs;} \ friend inline bool operator !=(int lhs, x rhs) \ {return lhs!=rhs.v_;} \ };
#define BOOST_STRONG_ENUM_NATIVE(x) x::enum_type #else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS
While this is not yet a complete emulation of scoped enums, it has the advantage of that there is no need to use a macro to name the strong type.
It looks decent, but shouldn't int be a computed type based upon the size and signed-ness of enum_type? Of course, you could also provide macros to specify the underlying type and use that, instead of enum_type, as the type of v_. That would increase compatibility with strongly typed enums in C++11. Why convert implicitly to int rather than to enum_type? You could convert to the computed type I mentioned above, but converting to enum_type would ensure the most appropriate conversions, wouldn't it? It might also be good to put the semicolon closing the enumerated type definition into the _END macro. That would increase symmetry and more strongly tie the _END macro to the construct: BOOST_DECLARE_STRONG_ENUM_BEGIN(cv_status) { no_timeout, timeout } BOOST_DECLARE_STRONG_ENUM_END(cv_status) It would be nice if the macros would produce strongly typed enums, when available, and devolve to emulation when not. It might also prove useful to have a macro to forward declare them: BOOST_FORWARD_DECLARE_STRONG_ENUM(name). That would forward declare a normal class, when emulating, and forward declare the enum class otherwise. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Le 25/01/12 13:26, Stewart, Robert a écrit :
Vicente J. Botet wrote:
Le 24/01/12 22:51, Beman Dawes a écrit :
What do others think? Should /boost/detail/scoped_enum_emulation.hpp functionality be moved to config?
Are there any improvements that would make the emulation better, without turning something simple into something complex? I'm working with a different emulation which uses classes. For example
// enum class cv_status; BOOST_DECLARE_STRONG_ENUM_BEGIN(cv_status) { no_timeout, timeout }; BOOST_DECLARE_STRONG_ENUM_END(cv_status)
The macros are defined as follows:
#ifdef BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) \ struct x { \ enum enum_type
#define BOOST_DECLARE_STRONG_ENUM_END(x) \ enum_type v_; \ inline x() {} \ inline x(enum_type v) : v_(v) {} \ inline operator int() const {return v_;} \ friend inline bool operator ==(x lhs, int rhs) \ {return lhs.v_==rhs;} \ friend inline bool operator ==(int lhs, x rhs) \ {return lhs==rhs.v_;} \ friend inline bool operator !=(x lhs, int rhs) \ {return lhs.v_!=rhs;} \ friend inline bool operator !=(int lhs, x rhs) \ {return lhs!=rhs.v_;} \ };
#define BOOST_STRONG_ENUM_NATIVE(x) x::enum_type #else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS
While this is not yet a complete emulation of scoped enums, it has the advantage of that there is no need to use a macro to name the strong type. It looks decent, but shouldn't int be a computed type based upon the size and signed-ness of enum_type? Of course, you could also provide macros to specify the underlying type and use that, instead of enum_type, as the type of v_. That would increase compatibility with strongly typed enums in C++11. The implicit underlying type is int. And yes, another set of macros could be provided to allow to specify the underlying type.
Why convert implicitly to int rather than to enum_type? You could convert to the computed type I mentioned above, but converting to enum_type would ensure the most appropriate conversions, wouldn't it? The conversion operator should be explicit and to the underlying type, which is int. I have to change it to use explicit conversion when the compiler supports it.
It might also be good to put the semicolon closing the enumerated type definition into the _END macro. That would increase symmetry and more strongly tie the _END macro to the construct:
BOOST_DECLARE_STRONG_ENUM_BEGIN(cv_status) { no_timeout, timeout } BOOST_DECLARE_STRONG_ENUM_END(cv_status) Yes, this is better.
It would be nice if the macros would produce strongly typed enums, when available, and devolve to emulation when not. Have you miss the else part?
#else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS
It might also prove useful to have a macro to forward declare them: BOOST_FORWARD_DECLARE_STRONG_ENUM(name). That would forward declare a normal class, when emulating, and forward declare the enum class otherwise.
Yes, this can be useful also. Next follows the new macros with the sugested improvements #ifdef BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT, UT) \ struct NT { \ typedef UT underlying_type; \ enum enum_type #ifndef BOOST_NO_EXPLICIT_CONVERSION_OPERATORS #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \ ; \ underlying_type v_; \ inline NT() {} \ inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \ inline explicit operator underlying_type() const {return underlying();} \ }; #else #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \ ; \ underlying_type v_; \ inline NT() {} \ inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \ inline operator underlying_type() const {return underlying();} \ }; #endif #define BOOST_DECLARE_STRONG_ENUM_BEGIN(NT) \ BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT,int) #define BOOST_DECLARE_STRONG_ENUM_END(NT) \ BOOST_DECLARE_STRONG_ENUM_UT_END(NT) #define BOOST_STRONG_ENUM_NATIVE(NT) NT::enum_type #define BOOST_FORWARD_DECLARE_STRONG_ENUM(NT) struct NT #else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT,UT) enum class NT:UT #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) ; #define BOOST_DECLARE_STRONG_ENUM_BEGIN(NT) enum class NT #define BOOST_DECLARE_STRONG_ENUM_END(NT) ; #define BOOST_STRONG_ENUM_NATIVE(NT) NT #define BOOST_FORWARD_DECLARE_STRONG_ENUM(NT) enum class NT #endif // BOOST_NO_SCOPED_ENUMS Thanks for the suggestions. Vicente

Vicente J. Botet wrote:
Le 25/01/12 13:26, Stewart, Robert a écrit :
Vicente J. Botet wrote:
It looks decent, but shouldn't int be a computed type based upon the size and signed-ness of enum_type? Of course, you could also provide macros to specify the underlying type and use that, instead of enum_type, as the type of v_. That would increase compatibility with strongly typed enums in C++11.
The implicit underlying type is int. And yes, another set of macros could be provided to allow to specify the underlying type.
I hadn't read enough about scoped enumerations before to see that the default type is exactly int, unlike unscoped enumerations.
Why convert implicitly to int rather than to enum_type? You could convert to the computed type I mentioned above, but converting to enum_type would ensure the most appropriate conversions, wouldn't it?
The conversion operator should be explicit and to the underlying type, which is int. I have to change it to use explicit conversion when the compiler supports it.
I see that now.
It would be nice if the macros would produce strongly typed enums, when available, and devolve to emulation when not.
Have you miss the else part?
#else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS
Yes, I overlooked that.
Next follows the new macros with the sugested improvements
#ifdef BOOST_NO_SCOPED_ENUMS
Did you mean the following? #ifndef BOOST_NO_SCOPED_ENUMS
#define BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT, UT) \
I wonder if preprocessor trickery could detect the difference between (NT) and (NT, UT) thereby permitting one macro to produce the right output regardless of whether the underlying type was given. Doing so might require extra parentheses, which might be perceived as worse than two macros.
struct NT { \ typedef UT underlying_type; \ enum enum_type
#ifndef BOOST_NO_EXPLICIT_CONVERSION_OPERATORS
#define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \
Since you're not asking the user to repeat UT, maybe this should just be BOOST_DECLARE_STRONG_ENUM_END. That is, use two different macros to introduce the scoped enumeration (if preprocessor tricks can't reduce that to one), but just use one macro to finalize them. Also, I think "DEFINE" is better than "DECLARE" because you're generating a definition (which is an implicit declaration). Furthermore, doing so would mean that "FORWARD_DECLARE" could be just "DECLARE", if you like.
; \ underlying_type v_; \ inline NT() {} \
Why "inline"? The definitions are provided inline, so the keyword adds nothing. ISTR that some compiler -- perhaps a very old one -- complains about such use of the inline keyword.
inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \
I've always preferred naming such functions with an "as_" prefix. In this context, you actually know the name of the underlying type, so you could even do as_##UT, though that wouldn't work right for unsigned int, signed int, etc. Maybe the preprocessor can help, for example, to collapse "unsigned int" to "unsigned" so you could generate "as_unsigned" even when UT is "unsigned int".
inline explicit operator underlying_type() const {return underlying();} \ }; #else #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \ ; \ underlying_type v_; \ inline NT() {} \ inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \ inline operator underlying_type() const {return underlying();} \ }; #endif
It looks to me as if you could simplify the above since the only difference between the sections, with and without BOOST_NO_EXPLICIT_CONVERSION_OPERATORS defined, is one operator. Thus: #ifndef BOOST_NO_EXPLICIT_CONVERSION_OPERATORS # define BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR \ inline explicit operator underlying_type() const \ {return underlying();} #else # define BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR \ inline operator underlying_type() const \ {return underlying();} #endif #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \ ; \ underlying_type v_; \ inline NT() {} \ inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \ BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR };
#define BOOST_DECLARE_STRONG_ENUM_BEGIN(NT) \ BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT,int)
#define BOOST_DECLARE_STRONG_ENUM_END(NT) \ BOOST_DECLARE_STRONG_ENUM_UT_END(NT)
#define BOOST_STRONG_ENUM_NATIVE(NT) NT::enum_type #define BOOST_FORWARD_DECLARE_STRONG_ENUM(NT) struct NT
#else // BOOST_NO_SCOPED_ENUMS
#define BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT,UT) enum class NT:UT #define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) ; #define BOOST_DECLARE_STRONG_ENUM_BEGIN(NT) enum class NT #define BOOST_DECLARE_STRONG_ENUM_END(NT) ;
#define BOOST_STRONG_ENUM_NATIVE(NT) NT #define BOOST_FORWARD_DECLARE_STRONG_ENUM(NT) enum class NT
#endif // BOOST_NO_SCOPED_ENUMS
Thanks for the suggestions.
NP One last thought: why "strong"? The standard calls them "scoped enumerations" so why not "SCOPED_ENUM_"? _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Vicente J. Botet wrote:
Le 25/01/12 13:26, Stewart, Robert a écrit :
Vicente J. Botet wrote: It looks decent, but shouldn't int be a computed type based upon the size and signed-ness of enum_type? Of course, you could also provide macros to specify the underlying type and use that, instead of enum_type, as the type of v_. That would increase compatibility with strongly typed enums in C++11. The implicit underlying type is int. And yes, another set of macros could be provided to allow to specify the underlying type. I hadn't read enough about scoped enumerations before to see that the default type is exactly int, unlike unscoped enumerations.
Why convert implicitly to int rather than to enum_type? You could convert to the computed type I mentioned above, but converting to enum_type would ensure the most appropriate conversions, wouldn't it? The conversion operator should be explicit and to the underlying type, which is int. I have to change it to use explicit conversion when the compiler supports it. I see that now.
It would be nice if the macros would produce strongly typed enums, when available, and devolve to emulation when not. Have you miss the else part?
#else // BOOST_NO_SCOPED_ENUMS #define BOOST_DECLARE_STRONG_ENUM_BEGIN(x) enum class x #define BOOST_DECLARE_STRONG_ENUM_END(x) #define BOOST_STRONG_ENUM_NATIVE(x) x #endif // BOOST_NO_SCOPED_ENUMS Yes, I overlooked that.
Next follows the new macros with the sugested improvements
#ifdef BOOST_NO_SCOPED_ENUMS Did you mean the following?
#ifndef BOOST_NO_SCOPED_ENUMS No. The true part is the emulated one. The else uses enum class.
#define BOOST_DECLARE_STRONG_ENUM_UT_BEGIN(NT, UT) \ I wonder if preprocessor trickery could detect the difference between (NT) and (NT, UT) thereby permitting one macro to produce the right output regardless of whether the underlying type was given. Doing so might require extra parentheses, which might be perceived as worse than two macros. Yes. Maybe this can be done easily.
struct NT { \ typedef UT underlying_type; \ enum enum_type
#ifndef BOOST_NO_EXPLICIT_CONVERSION_OPERATORS
#define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \
Since you're not asking the user to repeat UT, maybe this should just be BOOST_DECLARE_STRONG_ENUM_END. That is, use two different macros to introduce the scoped enumeration (if preprocessor tricks can't reduce that to one), but just use one macro to finalize them. I agree.
Also, I think "DEFINE" is better than "DECLARE" because you're generating a definition (which is an implicit declaration). Furthermore, doing so would mean that "FORWARD_DECLARE" could be just "DECLARE", if you like. I could consider that.
; \ underlying_type v_; \ inline NT() {} \
Why "inline"? The definitions are provided inline, so the keyword adds nothing. ISTR that some compiler -- perhaps a very old one -- complains about such use of the inline keyword. You are right. These inline seems unnecessary. I don't remember why I used them.
inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \
I've always preferred naming such functions with an "as_" prefix. In this context, you actually know the name of the underlying type, so you could even do as_##UT, though that wouldn't work right for unsigned int, signed int, etc. Maybe the preprocessor can help, for example, to collapse "unsigned int" to "unsigned" so you could generate "as_unsigned" even when UT is "unsigned int". I have no used underlying yet. It was just there to show a workaround when there is no explicit conversion. Anyway to make the user code
Le 26/01/12 14:56, Stewart, Robert a écrit : portable, he can not use the member function as enum class don't have it. That mean s that we need a non-member function, let me call it underlying_cast, namespace boost { #ifdef BOOST_NO_SCOPED_ENUMS template <typename UT, typename NT> UT underlying_cast(NT v) { return v.underlying(); } #else // BOOST_NO_SCOPED_ENUMS template <typename UT, typename NT> UT underlying_cast(NT v) { return static_cast<UT>(v); } #endif } The portable explicit conversion to the underlying type becomes int i = boost::underlying_cast<int>(e);
It looks to me as if you could simplify the above since the only difference between the sections, with and without BOOST_NO_EXPLICIT_CONVERSION_OPERATORS defined, is one operator. Thus:
#ifndef BOOST_NO_EXPLICIT_CONVERSION_OPERATORS
# define BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR \ inline explicit operator underlying_type() const \ {return underlying();}
#else
# define BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR \
#endif
#define BOOST_DECLARE_STRONG_ENUM_UT_END(NT) \ ; \ underlying_type v_; \ inline NT() {} \ inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return v_;} \ BOOST_DECLARE_STRONG_ENUM_UT_CONVERSION_OPERATOR };
Yes. We can use instead a macro to replace just explicit as it BOOST_CONSTEXPR is used for constexpr BOOST_EXPLICIT operator underlying_type() const \ {return underlying();} At the end I'm wondering if the implicit conversion should even be provided, so I will adopt the internal macro. After removing the implicit conversion I have added friend inline bool operator ==(NT lhs, enum_type rhs) {return enum_type(lhs.v_)==rhs;} \ friend inline bool operator ==(enum_type lhs, NT rhs) {return lhs==enum_type(rhs.v_);} \ friend inline bool operator !=(NT lhs, enum_type rhs) {return enum_type(lhs.v_)!=rhs;} \ friend inline bool operator !=(enum_type lhs, NT rhs) {return lhs!=enum_type(rhs.v_);} \
NP
One last thought: why "strong"? The standard calls them "scoped enumerations" so why not "SCOPED_ENUM_"?
I have no problems with renaming them. I will commit something on the sandbox soon so that we can continue improving it. Best, Vicente

Vicente J. Botet wrote:
Le 26/01/12 14:56, Stewart, Robert a écrit :
inline NT(enum_type v) : v_(v) {} \ inline underlying_type underlying() const {return
v_;} \
I've always preferred naming such functions with an "as_" prefix. In this context, you actually know the name of the underlying type, so you could even do as_##UT, though that wouldn't work right for unsigned int, signed int, etc. Maybe the preprocessor can help, for example, to collapse "unsigned int" to "unsigned" so you could generate "as_unsigned" even when UT is "unsigned int".
I have no used underlying yet. It was just there to show a workaround when there is no explicit conversion. Anyway to make the user code portable, he can not use the member function as enum class don't have it. That mean s that we need a non-member function, let me call it underlying_cast,
namespace boost { #ifdef BOOST_NO_SCOPED_ENUMS template <typename UT, typename NT> UT underlying_cast(NT v) { return v.underlying(); } #else // BOOST_NO_SCOPED_ENUMS template <typename UT, typename NT> UT underlying_cast(NT v) { return static_cast<UT>(v); } #endif }
The portable explicit conversion to the underlying type becomes
int i = boost::underlying_cast<int>(e);
That is better. The existence of underlying() is, then, an implementation detail. Indeed, you might name it something more ominous: "detail_as_underlying", perhaps.
At the end I'm wondering if the implicit conversion should even be provided
Without it, static_cast<underlying_type>(e) won't work, but that's valid for the real thing.
I will commit something on the sandbox soon so that we can continue improving it.
OK _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On Wed, Jan 25, 2012 at 8:51 AM, Beman Dawes <bdawes@acm.org> wrote:
It isn't a full emulation of C++11's scoped enum feature. That's probably why it ended up in detail rather than config, although I've forgotten the detailed rationale, if there ever was any.
What do others think? Should /boost/detail/scoped_enum_emulation.hpp functionality be moved to config?
Are there any improvements that would make the emulation better, without turning something simple into something complex?
--Beman
Thanks for responding. While I've got your attention, I have a similar question along the same lines. I notice in the mailing list archives that you added some noexcept related macros to Boost.Config on trunk back in October 2011, I can't see them in the current trunk or release though. What happened to those?
participants (4)
-
Beman Dawes
-
Joshua Boyce
-
Stewart, Robert
-
Vicente J. Botet Escriba