[C++0x] Emulation of scoped enums

The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers. See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a description. Note that the committee changed the name from strongly typed enums to scoped enums. See the attached for a boost/detail header that provides macro wrappers that use scoped enums if available, otherwise fall back on C++03 namespaces and unscoped enums. It lets a library write: BOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; BOOST_SCOPED_ENUM_END ... BOOST_SCOPED_ENUM(algae) sample( algae::red ); void func(BOOST_SCOPED_ENUM(algae)); and then a user can write: sample = algae::green; func( algae::cyan ); Comments or suggestions appreciated, --Beman // scoped_enum_emulation.hpp ---------------------------------------------------------// // Copyright Beman Dawes, 2009 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt // Generates C++0x scoped enums if the feature is present, otherwise emulates C++0x // scoped enums with C++03 namespaces and enums. The Boost.Config BOOST_NO_SCOPED_ENUMS // macro is used to detect feature support. // // Caution: only the syntax is emulated; the semantics are not emulated and // the syntax emulation doesn't include being able to specify the underlying type. // // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a // description of the feature. Note that the committee changed the name from // strongly typed enums to scoped enums. // // Sample usage: // // BOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; BOOST_SCOPED_ENUM_END // ... // BOOST_SCOPED_ENUM(algae) sample( algae::red ); // void foo( BOOST_SCOPED_ENUM(algae) color ); // ... // sample = algae::green; // foo( algae::cyan ); #ifndef BOOST_SCOPED_ENUM_EMULATION_HPP #define BOOST_SCOPED_ENUM_EMULATION_HPP #include <boost/config.hpp> #ifndef BOOST_NO_SCOPED_ENUMS # define BOOST_SCOPED_ENUM_START(name) enum class name # define BOOST_SCOPED_ENUM_END # define BOOST_SCOPED_ENUM(name) name #else # define BOOST_SCOPED_ENUM_START(name) namespace name { enum enum_t # define BOOST_SCOPED_ENUM_END } # define BOOST_SCOPED_ENUM(name) name::enum_t #endif #endif // BOOST_SCOPED_ENUM_EMULATION_HPP

I like it, iff you change the implementation from #ifndef BOOST_NO_SCOPED_ENUMS ... to #ifdef BOOST_NO_SCOPED_ENUMS I do have a hard time with double negations. Kjell E
Date: Thu, 5 Mar 2009 10:37:12 -0500 From: bdawes@acm.org To: boost@lists.boost.org Subject: [boost] [C++0x] Emulation of scoped enums
The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a description. Note that the committee changed the name from strongly typed enums to scoped enums.
See the attached for a boost/detail header that provides macro wrappers that use scoped enums if available, otherwise fall back on C++03 namespaces and unscoped enums. It lets a library write:
BOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; BOOST_SCOPED_ENUM_END ... BOOST_SCOPED_ENUM(algae) sample( algae::red ); void func(BOOST_SCOPED_ENUM(algae));
and then a user can write:
sample = algae::green; func( algae::cyan );
Comments or suggestions appreciated,
--Beman
_________________________________________________________________ Dela foton på ett smidigt sätt med Windows Live™ Photos. http://www.microsoft.com/windows/windowslive/products/photos.aspx

On Thu, Mar 5, 2009 at 10:45 AM, Kjell Elster <kjell_elster@hotmail.com> wrote:
I like it, iff you change the implementation from
#ifndef BOOST_NO_SCOPED_ENUMS ...
to
#ifdef BOOST_NO_SCOPED_ENUMS
I do have a hard time with double negations.
Point take. Will change. Thanks, --Beman

Beman Dawes wrote:
The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a description. Note that the committee changed the name from strongly typed enums to scoped enums.
See the attached for a boost/detail header that provides macro wrappers that use scoped enums if available, otherwise fall back on C++03 namespaces and unscoped enums. It lets a library write:
BOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; BOOST_SCOPED_ENUM_END ... BOOST_SCOPED_ENUM(algae) sample( algae::red ); void func(BOOST_SCOPED_ENUM(algae));
and then a user can write:
sample = algae::green; func( algae::cyan );
Good plan. Thoughts: - No need to make it a ::detail! - The user needs to spell out the macro if they declare a variable; can this be avoided? - How about avoiding the _START/_END stuff with e.g. BOOST_SCOPED_ENUM_DECL(algae, green,red,cyan); (I had been under the impression that varargs macros were a gcc-ism, but I've recently discovered that they're in c99; do non-gcc C++ compilers generally allow them? I don't think we can get away with allowing only up-to-N elements in this case.) - I agree with Kjell about the double negative :-) Phil.

Phil Endecott a écrit :
- How about avoiding the _START/_END stuff with e.g. BOOST_SCOPED_ENUM_DECL(algae, green,red,cyan); (I had been under the impression that varargs macros were a gcc-ism, but I've recently discovered that they're in c99; do non-gcc C++ compilers generally allow them? I don't think we can get away with allowing only up-to-N elements in this case.)
Evenif variadic macro is not supported, Boost::Preprocessor sequence can : BOOST_SCOPED_ENUM_DECL(algae, (green)(red)(cyan) ); or Boost::Preprocessor array BOOST_SCOPED_ENUM_DECL(algae, (3,(green,red,cyan) ); -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

On Thu, Mar 5, 2009 at 12:15 PM, Phil Endecott <spam_from_boost_dev@chezphil.org> wrote:
Good plan. Thoughts:
- No need to make it a ::detail!
- The user needs to spell out the macro if they declare a variable; can this be avoided?
- How about avoiding the _START/_END stuff with e.g. BOOST_SCOPED_ENUM_DECL(algae, green,red,cyan); (I had been under the impression that varargs macros were a gcc-ism, but I've recently discovered that they're in c99; do non-gcc C++ compilers generally allow them? I don't think we can get away with allowing only up-to-N elements in this case.)
Hum... I hadn't considered varargs macros. If I even knew they existed:-) Let me try that on some non-gcc compilers. I'll report back. Thanks, --Beman

On Thu, Mar 5, 2009 at 12:44 PM, Beman Dawes <bdawes@acm.org> wrote:
On Thu, Mar 5, 2009 at 12:15 PM, Phil Endecott
- How about avoiding the _START/_END stuff with e.g. BOOST_SCOPED_ENUM_DECL(algae, green,red,cyan); (I had been under the impression that varargs macros were a gcc-ism, but I've recently discovered that they're in c99; do non-gcc C++ compilers generally allow them? I don't think we can get away with allowing only up-to-N elements in this case.)
Hum... I hadn't considered varargs macros. If I even knew they existed:-)
Let me try that on some non-gcc compilers. I'll report back.
It looks like Microsoft 2005 and later and at least some others support varargs macros, so I'm investigating further. --Beman

On Thu, Mar 5, 2009 at 7:11 PM, Beman Dawes <bdawes@acm.org> wrote:
On Thu, Mar 5, 2009 at 12:44 PM, Beman Dawes <bdawes@acm.org> wrote:
On Thu, Mar 5, 2009 at 12:15 PM, Phil Endecott
- How about avoiding the _START/_END stuff with e.g. BOOST_SCOPED_ENUM_DECL(algae, green,red,cyan); (I had been under the impression that varargs macros were a gcc-ism, but I've recently discovered that they're in c99; do non-gcc C++ compilers generally allow them? I don't think we can get away with allowing only up-to-N elements in this case.)
Hum... I hadn't considered varargs macros. If I even knew they existed:-)
Let me try that on some non-gcc compilers. I'll report back.
It looks like Microsoft 2005 and later and at least some others support varargs macros, so I'm investigating further.
I wouldn't. If you really want to use one macro only, I would use the PP sequence instead.
--Beman
-- Felipe Magno de Almeida

I wouldn't. If you really want to use one macro only, I would use the PP sequence instead.
I'm gonna be the rebel and say that I think how it's currently implemented is [unfortunately] the most functional and most portable option, though I guess there is no harm in supplying a couple of interfaces as long as it doesn't make things too confusing for users. The problem with using a PP sequence is that you are going to hit a hard limit of 256 elements, meaning you have to at least support the current interface as an option otherwise you rule out using the macro for enums with a large number of constants. This also makes things frustrating for users if their enum starts below 256 in size and then over time approaches the limit. That means they would then have to go back and switch from using preprocessor sequences to the original style interface (or use a version of Boost.Preprocessor with higher limits). As for using variadic macros, you need either a compiler that supports them as an extension for C++, or an 0x compiler. While I agree that the current interface is kind of ugly, I still think it's the best option available. -- -Matt Calabrese

On Thu, Mar 5, 2009 at 9:26 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I wouldn't. If you really want to use one macro only, I would use the PP sequence instead.
I'm gonna be the rebel and say that I think how it's currently implemented is [unfortunately] the most functional and most portable option,
Actually I agree with you too. I just meant that I think the PP sequence would be better than using a vararg macro. Though I didn't know that it has a hard limit of 256 elements. [snip]
While I agree that the current interface is kind of ugly, I still think it's the best option available.
I don't really mind the current interface. What I find uglier is using a macro to use the enum type.
-- -Matt Calabrese
Regards, -- Felipe Magno de Almeida

Another potential issue with using PP sequences or other preprocessor containers is that if there is a comma in one of the initializers that isn't surrounded by parethesis (i.e. because it refers to a template with multiple arguments), then the user would have to provide additional parenthesis around their expression. To people not used to the preprocessor, this is not immediately apparent and only causes frustration because the errors produced are far from easy to comprehend on first glance. The current interface obviously avoids all of that. -- -Matt Calabrese

----- Original Message ----- From: "Felipe Magno de Almeida" <felipe.m.almeida@gmail.com> To: <boost@lists.boost.org> Sent: Friday, March 06, 2009 1:42 AM Subject: Re: [boost] [C++0x] Emulation of scoped enums
On Thu, Mar 5, 2009 at 9:26 PM, Matt Calabrese <rivorus@gmail.com> wrote:
While I agree that the current interface is kind of ugly, I still think it's the best option available.
I don't really mind the current interface. What I find uglier is using a macro to use the enum type.
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03. The initial proposal seems a good compromise to me. Vicente

2009/3/6 vicente.botet <vicente.botet@wanadoo.fr>:
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03.
A class is a name scope and a type - isn't that why it's called 'enum class'? class algae { public: enum value {green, red, cyan}; algae() {} algae(value v) : v_(v) {} // And any other required methods... private: value v_; }; algae x = algae::red; algae y = red; // error... This would also be closer to 'enum class' as it's strongly typed. Beman's preprocessing syntax would have to change, as the closing macro would have to know the name. The syntax using a preprocessor sequence or varargs would be the same. Daniel

----- Original Message ----- From: "Daniel James" <daniel_james@fmail.co.uk> To: <boost@lists.boost.org> Sent: Friday, March 06, 2009 12:39 PM Subject: Re: [boost] [C++0x] Emulation of scoped enums
2009/3/6 vicente.botet <vicente.botet@wanadoo.fr>:
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03.
A class is a name scope and a type - isn't that why it's called 'enum class'?
class algae { public: enum value {green, red, cyan};
algae() {} algae(value v) : v_(v) {}
// And any other required methods... private: value v_; };
algae x = algae::red; algae y = red; // error...
This would also be closer to 'enum class' as it's strongly typed.
Beman's preprocessing syntax would have to change, as the closing macro would have to know the name. The syntax using a preprocessor sequence or varargs would be the same.
Hi, The generated code of the macro can generate this or what Beman proposed. In any case the _START, _END will be needed. I like your solution because it allows to create a different type. I think that in addition it would be great to allows the storage type to be an integer type other that the enum value (emulation of the enum_base) In order to recall as much as possible the C++0X syntax enum class algae {green, red, cyan }; enum class mycolors : unsigned char {green, red, cyan }; what about BOOST_ENUM_CLASS_START(algae) { green, red, cyan }; BOOST_ENUM_CLASS_END BOOST_GENERIC_ENUM_CLASS_START(algae, unsigned char) { green, red, cyan }; BOOST_ENUM_CLASS_END And use BOOST_ENUM_CLASS(algae)? Best, Vicente Best, Vicente

Daniel James wrote:
2009/3/6 vicente.botet <vicente.botet@wanadoo.fr>:
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03.
A class is a name scope and a type - isn't that why it's called 'enum class'?
class algae { public: enum value {green, red, cyan};
algae() {} algae(value v) : v_(v) {}
// And any other required methods... private: value v_; };
algae x = algae::red; algae y = red; // error...
This would also be closer to 'enum class' as it's strongly typed.
Beman's preprocessing syntax would have to change, as the closing macro would have to know the name. The syntax using a preprocessor sequence or varargs would be the same.
I've worked a little bit with the class approach and it has a main portability issue. The use of user constructors disallows the use of the wrapper class in union (c++98 compilers), isn't it? If we don't have the conversion constructor. The following will fail at compile time algae x = algae::red; The same problem with a function returning the wrapper algae f() { return algae::red; } So either the class is not used on unions, either you will need to explicit conversion between the underlying enum type and the wrapper type. algae x = convert_to<algae>(algae::red); algae f() { return convert_to<algae>(algae::red); } I think that even if we need to use a macro to name the enum class type when writing portable code, the namespace approach seems to have less limitations. This doesn't mean that the class approach is not useful if you don't need to include the enum in a union or you work with compilers that allow already that even when there are user constructors (c++0x). But clearly, the approach can not be generalized to Boost, as Boost must be portable. Or, could it? Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/C-0x-Emulation-of-scoped-enums-tp2661312p... Sent from the Boost - Dev mailing list archive at Nabble.com.

Vicente Botet <vicente.botet@wanadoo.fr> writes:
Daniel James wrote:
2009/3/6 vicente.botet <vicente.botet@wanadoo.fr>:
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03.
A class is a name scope and a type - isn't that why it's called 'enum class'?
class algae { public: enum value {green, red, cyan};
algae() {} algae(value v) : v_(v) {}
// And any other required methods... private: value v_; };
algae x = algae::red; algae y = red; // error...
This would also be closer to 'enum class' as it's strongly typed.
Beman's preprocessing syntax would have to change, as the closing macro would have to know the name. The syntax using a preprocessor sequence or varargs would be the same.
This is the approach I've used; I much prefer it to the namespace-based approach.
I've worked a little bit with the class approach and it has a main portability issue.
The use of user constructors disallows the use of the wrapper class in union (c++98 compilers), isn't it?
Yes, but how often do you use unions? I very rarely use unions at all.
I think that even if we need to use a macro to name the enum class type when writing portable code, the namespace approach seems to have less limitations.
Having to use a macro whenever I mention the type name defeats the purpose of using scoped enums --- I might as well write algae::type if I have to write BOOST_SCOPED_ENUM(algae) Anthony -- Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/ just::thread C++0x thread library http://www.stdthread.co.uk Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Anthony Williams-4 wrote:
Vicente Botet <vicente.botet@wanadoo.fr> writes:
Daniel James wrote:
2009/3/6 vicente.botet <vicente.botet@wanadoo.fr>:
I don't think there is a better solution. You need to mask the fact that a enum type in C++0x is name scope and a type and can not be in C++03.
A class is a name scope and a type - isn't that why it's called 'enum class'?
class algae { public: enum value {green, red, cyan};
algae() {} algae(value v) : v_(v) {}
// And any other required methods... private: value v_; };
algae x = algae::red; algae y = red; // error...
This would also be closer to 'enum class' as it's strongly typed.
Beman's preprocessing syntax would have to change, as the closing macro would have to know the name. The syntax using a preprocessor sequence or varargs would be the same.
This is the approach I've used; I much prefer it to the namespace-based approach.
I've worked a little bit with the class approach and it has a main portability issue.
The use of user constructors disallows the use of the wrapper class in union (c++98 compilers), isn't it?
Yes, but how often do you use unions? I very rarely use unions at all.
I don't use to use them. When I need to probide an enum for my own usage, I think that the wrapper class will satisfy all my constraints. My concerns is if Boost libraries can provide public enum classes in his interface with an emulation that forbids a possible user to use it in a union, in particular for enum classes that appear in the C++0x recomendation?
I think that even if we need to use a macro to name the enum class type when writing portable code, the namespace approach seems to have less limitations.
Having to use a macro whenever I mention the type name defeats the purpose of using scoped enums --- I might as well write algae::type if I have to write BOOST_SCOPED_ENUM(algae)
I agree that the use of the macro to make code portable is nasty, but I don't know a better portable way. Of course, a user that is not concerned by portability issues, could use directly algae::type or algae depending on the compiler he is using. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/C-0x-Emulation-of-scoped-enums-tp2661312p... Sent from the Boost - Dev mailing list archive at Nabble.com.

----- Original Message ----- From: "Matt Calabrese" <rivorus@gmail.com> To: <boost@lists.boost.org> Sent: Friday, March 06, 2009 1:26 AM Subject: Re: [boost] [C++0x] Emulation of scoped enums
I wouldn't. If you really want to use one macro only, I would use the PP sequence instead.
I'm gonna be the rebel and say that I think how it's currently implemented is [unfortunately] the most functional and most portable option, though I guess there is no harm in supplying a couple of interfaces as long as it doesn't make things too confusing for users. The problem with using a PP sequence is that you are going to hit a hard limit of 256 elements, meaning you have to at least support the current interface as an option otherwise you rule out using the macro for enums with a large number of constants. This also makes things frustrating for users if their enum starts below 256 in size and then over time approaches the limit. That means they would then have to go back and switch from using preprocessor sequences to the original style interface (or use a version of Boost.Preprocessor with higher limits). As for using variadic macros, you need either a compiler that supports them as an extension for C++, or an 0x compiler. While I agree that the current interface is kind of ugly, I still think it's the best option available.
I agree, The _START _END version has a little inconvenient, but a lot of advanteges. Vicente

On Thu, Mar 5, 2009 at 8:26 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I wouldn't. If you really want to use one macro only, I would use the PP sequence instead.
I'm gonna be the rebel and say that I think how it's currently implemented is [unfortunately] the most functional and most portable option, though I guess there is no harm in supplying a couple of interfaces as long as it doesn't make things too confusing for users. The problem with using a PP sequence is that you are going to hit a hard limit of 256 elements, meaning you have to at least support the current interface as an option otherwise you rule out using the macro for enums with a large number of constants. This also makes things frustrating for users if their enum starts below 256 in size and then over time approaches the limit. That means they would then have to go back and switch from using preprocessor sequences to the original style interface (or use a version of Boost.Preprocessor with higher limits). As for using variadic macros, you need either a compiler that supports them as an extension for C++, or an 0x compiler. While I agree that the current interface is kind of ugly, I still think it's the best option available.
Good points. I agree. --Beman

on Thu Mar 05 2009, Matt Calabrese <rivorus-AT-gmail.com> wrote:
The problem with using a PP sequence is that you are going to hit a hard limit of 256 elements
Hm, I was under the impression that PP SEQs weren't limited in that way. Am I missing something? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

AMDG David Abrahams wrote:
on Thu Mar 05 2009, Matt Calabrese <rivorus-AT-gmail.com> wrote:
The problem with using a PP sequence is that you are going to hit a hard limit of 256 elements
Hm, I was under the impression that PP SEQs weren't limited in that way. Am I missing something?
Nearly everything in the PP library has a hard limit of 256. for instance, I see code like this for PP SEQs: # define BOOST_PP_SEQ_ELEM_0(x) x, BOOST_PP_NIL # define BOOST_PP_SEQ_ELEM_1(_) BOOST_PP_SEQ_ELEM_0 # define BOOST_PP_SEQ_ELEM_2(_) BOOST_PP_SEQ_ELEM_1 ... # define BOOST_PP_SEQ_ELEM_255(_) BOOST_PP_SEQ_ELEM_254 True, it's possible to create larger SEQs, but the PP library can't process them. In Christ, Steven Watanabe

Phil Endecott wrote:
- The user needs to spell out the macro if they declare a variable; can this be avoided?
I believe that if you use scoped enums, algae will be the name of the enum, otherwise algae is going to be the name of the namespace the num is in. Which is why the macro is required.

Beman Dawes wrote:
The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a description. Note that the committee changed the name from strongly typed enums to scoped enums.
See the attached for a boost/detail header that provides macro wrappers that use scoped enums if available, otherwise fall back on C++03 namespaces and unscoped enums. It lets a library write:
Could this be rewritten to use structs instead of namespaces? This would allow to declare enums nested in classes.

On Fri, Mar 6, 2009 at 1:08 PM, Andrey Semashev <andrey.semashev@gmail.com>wrote:
Could this be rewritten to use structs instead of namespaces? This would allow to declare enums nested in classes.
Agreed. In retrospect, this is pretty important now that it's been noticed. On Fri, Mar 6, 2009 at 6:39 AM, Daniel James <daniel_james@fmail.co.uk> wrote:
A class is a name scope and a type - isn't that why it's called 'enum class'?
class algae { public: enum value {green, red, cyan};
algae() {} algae(value v) : v_(v) {}
// And any other required methods... private: value v_; };
I worry about an implementation like this because it opens up a bunch of very subtle difference that could otherwise be avoided. For instance, perhaps the simples problem is that now decltype( algae::green ) is not equal to the "enum" type that is intended to be used (rather it is an actual enum nested in that type). One quick example of how this can show up as a problem in seemingly trivial code is operator overloading. Imagine a very simple color enum with enumerations "red = 1", "green = 2", "blue = 4", and let's say you decide to overload operator | to combine colors. If you write the overload using the type "color"... as long as at least one of your operands is not one of the enumerated constants named directly. For instance, color( red ) | color( blue ) works fine, however red | blue would not because the operator was overloaded for the encapsulating type as opposed to the nested value type! Another problem is that the type can no longer be referenced as a recognized enum type to the compiler, so you can't, for instance, use it directly as the type of a non-type template parameter (instead you would have to use, continuing the example above, color::value, which wouldn't work for compilers that actually support scoped enums). In the interest of creating the least amount of subtle differences, I think leaving the type as an actual enum type is going to be the best solution. -- -Matt Calabrese

2009/3/6 Matt Calabrese <rivorus@gmail.com>:
One quick example of how this can show up as a problem in seemingly trivial code is operator overloading. Imagine a very simple color enum with enumerations "red = 1", "green = 2", "blue = 4", and let's say you decide to overload operator | to combine colors. If you write the overload using the type "color"... as long as at least one of your operands is not one of the enumerated constants named directly. For instance, color( red ) | color( blue ) works fine, however red | blue would not because the operator was overloaded for the encapsulating type as opposed to the nested value type!
I would find occasionally writing 'algae(algae::red) | blue' less inconvenient than having to write 'BOOST_SCOPED_ENUM(algae)' whenever I wanted to use the type. Another possibility is to have the values as static members of algae, with type algae, which would fix your problem but would loose the nice syntax for giving the enumerators values.
Another problem is that the type can no longer be referenced as a recognized enum type to the compiler, so you can't, for instance, use it directly as the type of a non-type template parameter (instead you would have to use, continuing the example above, color::value, which wouldn't work for compilers that actually support scoped enums).
Not a problem, just always use the emulation.
In the interest of creating the least amount of subtle differences, I think leaving the type as an actual enum type is going to be the best solution.
Versus the ADL differences and implicit casts in the original solution? Which seem like more serious differences to me. Daniel

On Sat, Mar 7, 2009 at 5:55 AM, Daniel James <daniel_james@fmail.co.uk>wrote:
I would find occasionally writing 'algae(algae::red) | blue' less inconvenient than having to write 'BOOST_SCOPED_ENUM(algae)' whenever I wanted to use the type.
And the point is that this only further strays from how you use actual enums. If we are trying to emulate enum functionality, why would we make it so different to use. Post how you'd write your overloaded operators and how the definition would work for both an underlying emulated scoped enum implementation and an underlying native scoped enum implementation -- you're going to have to be overly verbose otherwise it won't work for both implementations. Another subtle issue is for you to show how you'd write a switch statement using the enum -- now that you have a class-type, you can't use instances of it as an argument to switch directly without first casting your "enum" to an actual enum (or calling a named function a that returns the same value for a native implementation and returns the underlying enum value for an emulated one). There is also the template problem I pointed out earlier. All of this means that with such an implementation you still have to provide a way to get the actual underlying enum type or value if you want to be able to use it in all of the ways an enum can be used. In the times where you need the actual type, you would again have to use a macro or a separate typedef also generated by the original macro invocation anyway, which is what you didn't like about the first implementation to begin with. If the main thing that bothers you is simply that in order to refer to the type you have to use a macro, then just typedef it once and refer to it that way.
Another possibility is to have the values as static members of algae, with type algae, which would fix your problem but would loose the nice syntax for giving the enumerators values.
This is really starting to stray from enums now, and IMO needlessly so. How would you call the macro in a way that resolves to a scoped enum on compilers that support scoped enums without using preprocessor sequences or variadic macros which have all of the pitfalls already mentioned earlier in this thread? As well, for both implementers and users of the macro, it makes it much more difficult to support the enum functionality of automatically setting the enumerated constants' value to 1 greater than than the previous constant, unless you plan on scrapping that functionality of enums entirely.
Another problem is that the type can no longer be referenced as a recognized enum type to the compiler, so you can't, for instance, use it directly as the type of a non-type template parameter (instead you would have to use, continuing the example above, color::value, which wouldn't work for compilers that actually support scoped enums).
Not a problem, just always use the emulation.
I think this is the only option if that implementation is to be used, but I thought the whole point was to make portable scoped enums that use the native implementation when possible. With all of the different functionality that this implementation implies and the fact that a scoped enum isn't even used under the hood when available makes me question if it should even be called SCOPED_ENUM at all if this route were taken.
In the interest of creating the least amount of subtle differences, I think leaving the type as an actual enum type is going to be the best solution.
Versus the ADL differences and implicit casts in the original solution? Which seem like more serious differences to me.
Actually, the struct solution suggested by Andrey gets rid of the ADL differences so that is not a problem. Implicit conversion would be the one remaining difference and all that a user needs to do to make that portable is add a cast when converting to int and be conscious of everything they are already familiar with from using regular enums. -- -Matt Calabrese

2009/3/7 Matt Calabrese <rivorus@gmail.com>:
And the point is that this only further strays from how you use actual enums. If we are trying to emulate enum functionality, why would we make it so different to use. Post how you'd write your overloaded operators and how the definition would work for both an underlying emulated scoped enum implementation and an underlying native scoped enum implementation -- you're going to have to be overly verbose otherwise it won't work for both implementations.
I was looking at the proposal and the current draft of the C++0x standard to see how this should be implemented. And it isn't very clear. I don't think you can use '|' with scoped enums, because it requires its arguments to be converted to integers. If that's true then I wouldn't implement it. I might be wrong since I'm not familiar with the core language chapters of the standard, so maybe an expert could chime in? The Visual C++ implementation might give a clue about the intent but I don't have access to it at the moment.
Another subtle issue is for you to show how you'd write a switch statement using the enum -- now Cthat you have a class-type, you can't use instances of it as an argument to switch directly without first casting your "enum" to an actual enum (or calling a named function a that returns the same value for a native implementation and returns the underlying enum value for an emulated one).
Yep, good point. I'd have a method to return the value, which is a bit nasty: switch(x.get()) { case algae::red: // etc...
There is also the template problem I pointed out earlier.
As you suggested, 'template <algae::value x>'. I don't see it as particularly onerous. But that might be because I almost never use enums like that. Maybe it would be painful for people who make heavier use of templates than I do.
All of this means that with such an implementation you still have to provide a way to get the actual underlying enum type or value if you want to be able to use it in all of the ways an enum can be used. In the times where you need the actual type, you would again have to use a macro or a separate typedef also generated by the original macro invocation anyway, which is what you didn't like about the first implementation to begin with.
No it wasn't. In my first email I sent a potential solution to a comment by Vicente. And mentioned that I was pleased by the improved type safety. In my second I did say I would find the macro inconvenient, but was more worried about ADL and implicit casts.
Another possibility is to have the values as static members of algae, with type algae, which would fix your problem but would loose the nice syntax for giving the enumerators values.
This is really starting to stray from enums now, and IMO needlessly so. How would you call the macro in a way that resolves to a scoped enum on compilers that support scoped enums without using preprocessor sequences or variadic macros which have all of the pitfalls already mentioned earlier in this thread?
The pitfalls were commas in enumerator values and a 256 element limit. The first is rare (at least for me...) and easy to work around - just put brackets round the value. The second is perhaps more likely, and something of a problem. I think it's pretty easy to implement a higher limit, but there will always be a fixed limit. But I see loosing full support for enumerator values as a big loss.
As well, for both implementers and users of the macro, it makes it much more difficult to support the enum functionality of automatically setting the enumerated constants' value to 1 greater than than the previous constant, unless you plan on scrapping that functionality of enums entirely.
I meant to imply that by 'the nice syntax for giving the enumerators values', sorry that I wasn't precise.
just always use the emulation.
I think this is the only option if that implementation is to be used
I think I'd say the same for the alternative because of implicit casts.
but I thought the whole point was to make portable scoped enums that use the native implementation when possible.
But what's the point of using scoped enums? Beman started this thread with, 'The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers.'
With all of the different functionality that this implementation implies and the fact that a scoped enum isn't even used under the hood when available makes me question if it should even be called SCOPED_ENUM at all if this route were taken.
Fine with me.
Actually, the struct solution suggested by Andrey gets rid of the ADL differences so that is not a problem.
That's a big improvement.
Implicit conversion would be the one remaining difference and all that a user needs to do to make that portable is add a cast when converting to int and be conscious of everything they are already familiar with from using regular enums.
No, it's more complicated than that. For an example, because unscoped enums are implicitly convertible to ints, Boost.Hash supports them but doesn't support scoped enums (something for my todo list, although there doesn't seem to be a way to get the underlying type of the enum so it might be tricky). If you use Beman's SCOPED_ENUM with any of the boost containers that use boost::hash, you'll find that your code will break when using a compiler that supports real scoped enums. I'd expect other similar problems to appear in generic code. It's an issue if the current version is more permissive than the future one. We usually want things to fail sooner rather than later. Daniel

Andrey Semashev wrote:
Beman Dawes wrote:
The improved type safety of the C++0x scoped enum feature is attractive, so I'd like to start using it as it becomes available in compilers.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a description. Note that the committee changed the name from strongly typed enums to scoped enums.
See the attached for a boost/detail header that provides macro wrappers that use scoped enums if available, otherwise fall back on C++03 namespaces and unscoped enums. It lets a library write:
Could this be rewritten to use structs instead of namespaces? This would allow to declare enums nested in classes.
Ha! Good point! Changed. --Beman
participants (14)
-
Andrey Semashev
-
Anthony Williams
-
Beman Dawes
-
Daniel James
-
David Abrahams
-
Felipe Magno de Almeida
-
Joel Falcou
-
Kjell Elster
-
Mathias Gaunard
-
Matt Calabrese
-
Phil Endecott
-
Steven Watanabe
-
Vicente Botet
-
vicente.botet