Re: [boost] BOOST_ENUM proposal

----Original Message---- From: Frank Laub [mailto:frank.laub@gmail.com] Sent: 07 December 2005 11:47 To: boost@lists.boost.org Subject: [boost] BOOST_ENUM proposal
Hello fellow boosters,
I've recently come up with a way to use the boost preprocesor to generate a 'better' enum type. The following is an example of some typical usage. Is anyone else interested in this sort of thing?
**YES**!!
I'm hoping to get suggestions for how to make it more 'boost-like' in both its implementation and its usage. Is this very readable? Is there a place I can upload the code for people to peruse?
#include <iostream> #include <boost/enum.hpp> #include <boost/foreach.hpp> #define foreach BOOST_FOREACH I hope that this line is just needed for the demo code in main.
BOOST_ENUM(Level, (Abort)("unrecoverable problem") (Error)("recoverable problem") (Alert)("unexpected behavior") (Info)("expected behavior") (Trace)("normal flow of execution") (Debug)("detailed object state listings") )
Now we come to the meat of the problem. Here you have defined 'Level' at directly in a cpp file. Normally, I would want to define an enum in a header file, and I see potential problems with violations of the one-definition-rule. Also: does your implementation cope with defining an enum inside a class? (I could live with an answer of "No" - I would just have to put the enum outside the class.) Is your implementation limited to 255 elements (normal boost preprocessor limit)? Can I specify enum values (ie Abort=0, Info=16)?
int main() { foreach(const string& name, Level::names) { cout << name << endl; } cout << "1: " << Level::names[1] << endl; cout << "toString(Abort): " << Level::toString(Level::Abort) << endl; cout << "getValue(Abort): " << Level::getValue(Level::Abort) << endl;
Level::type value = Level::Invalid; bool ret = Level::fromString("Abort", value); cout << "fromString(\"Abort\"): " << ret << ", " << value << endl;
value = Level::Invalid; ret = Level::fromString("Debug", value); cout << "fromString(\"Debug\"): " << ret << ", " << value << endl;
value = Level::Invalid; ret = Level::fromString("not in enum", value); cout << "fromString(\"not in enum\"): " << ret << ", " << value << endl;
return 0; }
With the program output being:
Abort Error Alert Info Trace Debug Invalid 1: Error toString(Abort): Abort getValue(Abort): unrecoverable problem fromString("Abort"): 1, 0 fromString("Debug"): 1, 5 fromString("not in enum"): 0, 6
-Frank
-- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434

There should be no problems using this macro in a header file. I get around the one definition rule by simply making the enum actually be a namespace with static functions inside that namespace. So basically: BOOST_ENUM(Foo, (a)(b)) expands into: namespace Foo { enum type { a, b, size = 2, Invalid = -1 }; typedef boost::array<const std::string, size+1> array_type; static const array_type names = { "a", "b", "2" }; static const std::string& str(type index) { assert(index >= 0 && index <= size); return names[(int)index]; } static bool parse(const std::string& str, type& value) { array_type::const_iterator it = std::find(names.begin(), names.end(), str); if(it == names.end()) return false; value = (type)(it - names.begin()); return true; } static std::ostream& operator << (std::ostream& os, type value) { os << str(value); return os; } } On 12/7/05, Martin Bonner <martin.bonner@pitechnology.com> wrote:
----Original Message---- From: Frank Laub [mailto:frank.laub@gmail.com] Sent: 07 December 2005 11:47 To: boost@lists.boost.org Subject: [boost] BOOST_ENUM proposal
Hello fellow boosters,
I've recently come up with a way to use the boost preprocesor to generate a 'better' enum type. The following is an example of some typical usage. Is anyone else interested in this sort of thing?
**YES**!!
I'm hoping to get suggestions for how to make it more 'boost-like' in both its implementation and its usage. Is this very readable? Is there a place I can upload the code for people to peruse?
#include <iostream> #include <boost/enum.hpp> #include <boost/foreach.hpp> #define foreach BOOST_FOREACH I hope that this line is just needed for the demo code in main.
BOOST_ENUM(Level, (Abort)("unrecoverable problem") (Error)("recoverable problem") (Alert)("unexpected behavior") (Info)("expected behavior") (Trace)("normal flow of execution") (Debug)("detailed object state listings") )
Now we come to the meat of the problem. Here you have defined 'Level' at directly in a cpp file. Normally, I would want to define an enum in a header file, and I see potential problems with violations of the one-definition-rule.
Also: does your implementation cope with defining an enum inside a class? (I could live with an answer of "No" - I would just have to put the enum outside the class.)
Is your implementation limited to 255 elements (normal boost preprocessor limit)?
Can I specify enum values (ie Abort=0, Info=16)?
int main() { foreach(const string& name, Level::names) { cout << name << endl; } cout << "1: " << Level::names[1] << endl; cout << "toString(Abort): " << Level::toString(Level::Abort) << endl; cout << "getValue(Abort): " << Level::getValue(Level::Abort) << endl;
Level::type value = Level::Invalid; bool ret = Level::fromString("Abort", value); cout << "fromString(\"Abort\"): " << ret << ", " << value << endl;
value = Level::Invalid; ret = Level::fromString("Debug", value); cout << "fromString(\"Debug\"): " << ret << ", " << value << endl;
value = Level::Invalid; ret = Level::fromString("not in enum", value); cout << "fromString(\"not in enum\"): " << ret << ", " << value << endl;
return 0; }
With the program output being:
Abort Error Alert Info Trace Debug Invalid 1: Error toString(Abort): Abort getValue(Abort): unrecoverable problem fromString("Abort"): 1, 0 fromString("Debug"): 1, 5 fromString("not in enum"): 0, 6
-Frank
-- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Frank Laub wrote:
There should be no problems using this macro in a header file. I get around the one definition rule by simply making the enum actually be a namespace with static functions inside that namespace. So basically:
BOOST_ENUM(Foo, (a)(b))
expands into:
namespace Foo { enum type { a, b, size = 2, Invalid = -1 };
typedef boost::array<const std::string, size+1> array_type;
Is it not possible to go for typedef boost::array<const char*, size+1> array_type ?
static const array_type names = { "a", "b", "2" };
static const std::string& str(type index) { assert(index >= 0 && index <= size); return names[(int)index]; }
and maybe a CT version: template< type index > inline const char* str() { BOOST_STATIC_ASSERT( index > Invalid ); return names[(int)index]; } -Thorsten

Is it not possible to go for
typedef boost::array<const char*, size+1> array_type
?
Ah, yes, that's a terrific suggestion. Thanks. and maybe a CT version:
template< type index > inline const char* str() { BOOST_STATIC_ASSERT( index > Invalid ); return names[(int)index]; }
This is good too, but I think I'd still want a runtime version so that I can use it for an ostream operator. It seems a little weird to use: const char* str = Level::str<Level::Error>(); Hmm, wish it could look more elegant :p

Also: does your implementation cope with defining an enum inside a class?
(I could live with an answer of "No" - I would just have to put the enum outside the class.)
Nope, currently this doesn't work. Maybe there's some trick to perform here? Is your implementation limited to 255 elements (normal boost preprocessor
limit)?
Yes, its actually limited the max number of elements in a sequence, divided by 2. Can I specify enum values (ie Abort=0, Info=16)? I was just experimenting with that, and while the compiler does not complain if you do that, the parse() function simply doesn't work. I'd need a separate data element to describe the value portion, and then I'd have to throw that into a map so that parse can look it up by that value. I've begun to think perhaps I should split up the enum into 4 types: 1) BOOST_ENUM 2) BOOST_ENUM_COMMENTS 3) BOOST_ENUM_VALUES 4) BOOST_ENUM_COMMENTS_VALUES 1) would only allow you to specify the names for each element in the enum, e.g.: BOOST_ENUM(Boolean, (True) (False) ) 2) Let's you specify comments for each element, e.g.: BOOST_ENUM_COMMENTS(Colors, (Red)("Like an apple") (Orange)("Like an orange") ) 3) This one I'm still working on, but you should be able to do this: BOOST_ENUM_VALUES( (A)(0x10) (B)(0x20) ) 4) This is the most complex one, but you could do: BOOST_ENUM_COMMENTS_VALUES( (A)(0x10)("This is an A") (B)(0x20)("This is a B") ) I was also thinking how neat it would be to let the value portion of an element be whatever type the user wanted it to be, instead of it just having to be an integer. Well, this idea is just a muse, not sure if it really can be done or is even that desirable. -Frank

Frank Laub wrote:
Also: does your implementation cope with defining an enum inside a class?
(I could live with an answer of "No" - I would just have to put the enum outside the class.)
Nope, currently this doesn't work. Maybe there's some trick to perform here?
There should be no problems using this macro in a header file. I get around the one definition rule by simply making the enum actually be a namespace with static functions inside that namespace.
Just change 'namespace' to 'struct' and I think you should be set :) -Jason

Just change 'namespace' to 'struct' and I think you should be set :)
Hmm, I tried this but I got compiler errors. The problem is I won't be able to set the names collection in a header, that's because you can't set an array of non-integral type inside the declaration of a struct. You have to provide storage for it in a .cpp. Is there perhaps something I'm missing here?

Frank Laub wrote:
Just change 'namespace' to 'struct' and I think you should be set :)
Hmm, I tried this but I got compiler errors. The problem is I won't be able to set the names collection in a header, that's because you can't set an array of non-integral type inside the declaration of a struct. You have to provide storage for it in a .cpp. Is there perhaps something I'm missing here? _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Would it work to provide storage for it in a static function inside the struct? If you need to keep the same syntax you could create a proxy class to access it, something like this (untested): struct myenum { static struct { private: static char * namestorage ( ) { static char namearray[] = { "yadda", "stuff", "etc" }; return namearray; } public: char * operator [] ( int index ) { return namestorage ( )[index]; } } names; }; -Jason

Thanks a lot for this suggestion. It inspired me to write version 2. In this approach, the macro expansion only produces a type that contains the underlying enum and storage(), which contains all the strings. The trick now is that there is: template <typename base> struct safe_enum : base; The macro now expands: BOOST_ENUM(Boolean, (False) (True) ) to: class Boolean_base { public: enum type { False, True, size = 2, Invalid = -1 }; protected: typedef boost::array<const char*, (size)+1> array_type; static const array_type& storage() { static const array_type names = { "False", "True", "2" }; return names; } }; typedef safe_enum<Boolean_base> Boolean; The Boolean now gets the following methods from safe_enum: begin() end() operator[] str() (CT and RT versions) parse() I was thinking of re-naming the other kind of enum that I had before (BOOST_ENUM_COMMENTS) to something like BOOST_STRINGTABLE, since that's really the intention. I've uploaded v2 to the file vault under Preprocessor Metaprogramming. I'd love to hear more suggestions or even complaints! Thanks a ton, -Frank

On 12/08/2005 11:45 PM, Frank Laub wrote: [snip]
I've uploaded v2 to the file vault under Preprocessor Metaprogramming. I'd love to hear more suggestions or even complaints!
Hi Frank, Before the next version, could you make the include guards more like those of the existing preprocessor library (especially since __ is not standard )? IOW, something like: #ifndef BOOST_PREPROCESSOR_ENUM_HPP #define BOOST_PREPROCESSOR_ENUM_HPP , and, in the same vein, give the macro names BOOST_PP prefixes? BTW, thanks for the work! -regards Larry

On 12/09/2005 06:54 AM, Larry Evans wrote:
On 12/08/2005 11:45 PM, Frank Laub wrote: [snip]
, and, in the same vein, give the macro names BOOST_PP prefixes?
Oh, one more thing. Add a copyright comment at the top, again, like the other boost .hpp files. Thanks.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Larry Evans
Before the next version, could you make the include guards more like those of the existing preprocessor library
This library is a client of the preprocessor library. It isn't component-like (in the context of the pp-lib). There isn't a single pp-lib component that takes input and produces a valid C or C++ construct. Instead, it has components that are geared toward the manipulation of tokens such that users can use the pp-lib to produce valid C or C++ constructs. It belongs at either the Boost root or its own library directory, not in the pp-lib. Regards, Paul Mensonides

#ifndef BOOST_PREPROCESSOR_ENUM_HPP #define BOOST_PREPROCESSOR_ENUM_HPP
, and, in the same vein, give the macro names BOOST_PP prefixes?
I've elected to keep it out of the preprocessor lib for now given Paul's comments. But I have gone ahead and prefixed the macro names with BOOST_ENUM_, is this sufficient? Also the guard is named BOOST_ENUM_HPP, hope that works. BTW, thanks for the work! Thanks for taking the time to check it out :) Oh, is there a way to undef the macros after I'm done using them? I've seen this in other boost libs but when I try I get a bunch of errors. How do local macros work? -Frank

On 12/09/2005 06:46 PM, Frank Laub wrote:
#ifndef BOOST_PREPROCESSOR_ENUM_HPP #define BOOST_PREPROCESSOR_ENUM_HPP
, and, in the same vein, give the macro names BOOST_PP prefixes?
I've elected to keep it out of the preprocessor lib for now given Paul's comments. But I have gone ahead and prefixed the macro names with
I see Paul's point.
BOOST_ENUM_, is this sufficient? Also the guard is named BOOST_ENUM_HPP, hope that works.
Looks good to me.
Thanks for taking the time to check it out :)
Most welcome.
Oh, is there a way to undef the macros after I'm done using them? I've seen this in other boost libs but when I try I get a bunch of errors. How do local macros work?
All I do is just mimic what other booster's have done: Have a *prefix file which defines them, and a *suffix file which undefines them. I'd just look around for something like that.

Frank Laub wrote:
BOOST_ENUM(Boolean, (False) (True) )
This looks really nice, especially if you could get the _VALUES version. I'd very much like to see something like that in Boost.
to:
class Boolean_base { public: enum type { False, True, size = 2, Invalid = -1 };
protected: typedef boost::array<const char*, (size)+1> array_type; static const array_type& storage() { static const array_type names = { "False", "True", "2" }; return names; } }; typedef safe_enum<Boolean_base> Boolean;
A few small remarks: I doubt if the storage array needs to be 'size+1' large. The last element of the size itself doesn't need to be stringized. The size value of the enum type itself can be moved outside to be a 'const size_t size = 2;'. I'm not sure that it really matters, I just think it's more elegant. But of course you can disagree... I also think the addition of the 'Invalid' value is not needed. If the enum::type would have been default constructed to 'Invalid', then there might be justification for this. But AFAICS, this is not the case, so IMO it's better removed. The user can always add it himself. BTW, the example in your first message showed a 'foreach(..., Level::names)' printing all values including "Invalid", not including the size. Accroding to the implemenation I see here, this seems to be impossible. Or did I miss anything? Yuval

This looks really nice, especially if you could get the _VALUES version. I'd very much like to see something like that in Boost.
I'm in the midst of completing this feature.. almost there! What do you think a good name for it is? BOOST_ENUM_VALUES or BOOST_STRINGTABLE or something else maybe? I doubt if the storage array needs to be 'size+1' large. The last
element of the size itself doesn't need to be stringized.
The reason I did this is because my preprocessor fu is not strong enough. The problem is how to deal with the trailing comma at the end.. my hack is to place another 'trailing' field to keep from having syntax errors. The size value of the enum type itself can be moved outside to be a
'const size_t size = 2;'. I'm not sure that it really matters, I just think it's more elegant. But of course you can disagree...
Ya, I could see the size being outside.. but because of my trailing comma concern, thought I'd kill two birds with one stone. I also think the addition of the 'Invalid' value is not needed. If the
enum::type would have been default constructed to 'Invalid', then there might be justification for this. But AFAICS, this is not the case, so IMO it's better removed. The user can always add it himself.
In all the actualy uses of this thing I've always needed an 'Invalid' field which is specifically used for things like default ctors. I can see how some users would rather add it themselves.. maybe they're worried about clashes. Perhaps there is a way to make the enum type be more than just a class-type (or a type with only static members on it). I was toying with an instanciable enum type, but I haven't gotten too far with it. BTW, the example in your first message showed a 'foreach(...,
Level::names)' printing all values including "Invalid", not including the size. Accroding to the implemenation I see here, this seems to be impossible. Or did I miss anything?
Ah, that was an older version, the current version should print the size at the end, minus the Invalid. Good catch! Thanks for all the comments! -Frank

Frank Laub wrote:
This looks really nice, especially if you could get the _VALUES version. I'd very much like to see something like that in Boost.
I'm in the midst of completing this feature.. almost there! What do you think a good name for it is? BOOST_ENUM_VALUES or BOOST_STRINGTABLE or something else maybe?
When I say 'the _VALUES version', I mean the version which assign numerical values to enum values, so I think BOOST_ENUM_VALUES (in addition to BOOST_ENUM with no numerical values) is just fine.
I doubt if the storage array needs to be 'size+1' large. The last element of the size itself doesn't need to be stringized.
The reason I did this is because my preprocessor fu is not strong enough. The problem is how to deal with the trailing comma at the end.. my hack is to place another 'trailing' field to keep from having syntax errors.
I don't think the comma at the end is a problem. If I'm not mistaken, the C++ compiler (not preprocessor) should be able to handle these last-commas-with-nothing-after-them. The preprocessor need not deal with it.
The size value of the enum type itself can be moved outside to be a 'const size_t size = 2;'. I'm not sure that it really matters, I just think it's more elegant. But of course you can disagree...
Ya, I could see the size being outside.. but because of my trailing comma concern, thought I'd kill two birds with one stone.
Well, if you can solve the comma issue... And of course the 'size' member should be 'static'. But you probably got it yourself...
I also think the addition of the 'Invalid' value is not needed. If the enum::type would have been default constructed to 'Invalid', then there might be justification for this. But AFAICS, this is not the case, so IMO it's better removed. The user can always add it himself.
In all the actualy uses of this thing I've always needed an 'Invalid' field which is specifically used for things like default ctors. I can see how some users would rather add it themselves.. maybe they're worried about clashes. Perhaps there is a way to make the enum type be more than just a class-type (or a type with only static members on it). I was toying with an instanciable enum type, but I haven't gotten too far with it.
An instanciable enum is a good idea. safe_enum would contain a non-static data member of type 'type', a default ctor, a ctor taking 'type', operator=, etc... This would allow users to write Level my_level; instead of Level::type my_level; which makes your enum more like native enums. I think this will appeal to users. However, I still don't think that an instanciable enum, even with default ctor initializing to 'Invalid' justifies the 'Invalid' value. If the user wants a not-initialized state, he can always add this value himself, or even better, use boost::optional which was created for this purpose exactly. No need to burden all users with another value to take care for.
BTW, the example in your first message showed a 'foreach(..., Level::names)' printing all values including "Invalid", not including the size. Accroding to the implemenation I see here, this seems to be impossible. Or did I miss anything?
Ah, that was an older version, the current version should print the size at the end, minus the Invalid. Good catch!
And even more important then the 'names' array, would be a 'values' array which holds the possible values, and can be for_each()ed. I think most users would use this array and not the 'names' array... In the regular version users can do a 'for (int i = 0; i < Level::size; i++)', but with the _VALUES version they must have this 'values' array. I'd even say that when you get the 'values' array operatioal, you can move the 'names' array to be private. Users have the str() function if they want. Keep up the good work! Yuval

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Yuval Ronen
to:
class Boolean_base { public: enum type { False, True, size = 2, Invalid = -1 };
protected: typedef boost::array<const char*, (size)+1> array_type; static const array_type& storage() { static const array_type names = { "False", "True", "2" }; return names; } }; typedef safe_enum<Boolean_base> Boolean;
A few small remarks:
I doubt if the storage array needs to be 'size+1' large. The last element of the size itself doesn't need to be stringized.
I haven't really been following this conversion, but why do you need an array at all? You have a sequence containing enumerator names. You can generate a switch statement just as easily as you can the enum itself: switch (v) { case False: return "False"; case True: return "True"; // etc. Regards, Paul Mensonides

Paul Mensonides wrote:
I haven't really been following this conversion, but why do you need an array at all? You have a sequence containing enumerator names. You can generate a switch statement just as easily as you can the enum itself:
switch (v) { case False: return "False"; case True: return "True"; // etc.
I guess that's a possibility... One point in favour of array, is that it ensures us of O(1) lookup time. A good compiler might do that with switch/case but I'm not sure it's something that we can rely on. My knowledge in these compiler optimization issues is definitely not that extended. For the _VALUES version, BTW, an array won't cut it, because the numbers aren't nicely ordered from 0 to size - 1. It needs to a map, or a switch/case, and I'm not really sure which is better... Yuval

On 12/10/2005 09:09 AM, Yuval Ronen wrote:
Paul Mensonides wrote:
I haven't really been following this conversion, but why do you need an array at all? You have a sequence containing enumerator names. You can generate a switch statement just as easily as you can the enum itself: [snip] One point in favour of array, is that it ensures us of O(1) lookup time. A good compiler might do that with switch/case but I'm not sure it's something that we can rely on. [snip] Actually, Andy Little did a comparison which showed the switch was faster than the array:
http://groups.google.com/group/comp.lang.c++.moderated/msg/6de73412e552c387

Larry Evans wrote:
On 12/10/2005 09:09 AM, Yuval Ronen wrote:
One point in favour of array, is that it ensures us of O(1) lookup time. A good compiler might do that with switch/case but I'm not sure it's something that we can rely on.
Actually, Andy Little did a comparison which showed the switch was faster than the array:
http://groups.google.com/group/comp.lang.c++.moderated/msg/6de73412e552c387
I'm not really sure, but I have feeling the switch/case advantage is marginal (am I right?). And another thing I'm not sure of is whether this must be the case with all compilers. If not, then I think I prefer a good algorithm to relying on compiler optimization which might not be so good in compilers other than those tested in this test. But that's just me...

On 12/10/2005 06:55 AM, Paul Mensonides wrote: [snip]
I haven't really been following this conversion, but why do you need an array at all? You have a sequence containing enumerator names. You can generate a switch statement just as easily as you can the enum itself:
switch (v) { case False: return "False"; case True: return "True"; // etc.
Regards, Paul Mensonides
Hmm... An array *seems* "cleaner" or "more object-oriented". I only say more "object-oriented" because switch statements were used before there were virtual functions. However, maybe that's my prejudice, and I'll admit "cleaner" and "more object-oriented" are pretty nebulous. Anyway, an example of generating such a switch statement is in vault under "Template Metaprogramming" in PP_RECFLD.zip. The array version of the same code is in little.funvec_.zip in little.funvec_constcvec.cpp.

Frank Laub wrote:
class Boolean_base { protected: typedef boost::array<const char*, (size)+1> array_type; static const array_type& storage() { static const array_type names = { "False", "True", "2" }; return names; } };
One more thing: using static data inside a function usually introduces thread-safety issues. I'm not sure if boost::array suffers from this, but I think it worth a check. If there is a problem, you might want to switch to native C++ arrays, or get some help from Jason's singleton...

Yuval Ronen wrote:
One more thing: using static data inside a function usually introduces thread-safety issues. I'm not sure if boost::array suffers from this, but I think it worth a check. If there is a problem, you might want to switch to native C++ arrays, or get some help from Jason's singleton...
First, we have to remember that boost::array pretends to be a POD type by not having any constructors or destructors. This means that a compiler might allocate the static in preset storage, thus removing all thread safety issues. I don't know if it's required to do so, though. If it doesn't, then the constructor for boost::array must be called and there are two scenarios. 1) The compiler generates a first_entry flag and sets it immediately upon entering. In this case, a thread might attempt to use the array before it's finished constructing. Access violations for the strings would be the result. 2) The compiler generates a statics_constructed that gets set after all constructors have finished. In this case, two threads might both try to construct the array. The trivial nature of boost::array means that there are no issues with this. I don't think any sane compiler would go for option 1, but I can't know for sure. Can anybody with the standard resolve the POD issue? If the compiler is required to allocate the array in preset storage, there are definitely no issues. Sebastian Redl

Very nice looking library =) One addition I'd like to see would be a BOOST_ENUM_MASKS or similar: BOOST_ENUM_MASKS( orders, (can_move) (can_patrol) (can_fire) ) and etc, where can_move would get 1<<0, can_patrol would get 1<<1, and etc, so that they could be combind. Automatic "none" and "all" ones would be nice too. orders::type allowed_orders = orders::can_fire|orders::can_move; std::cout << allowed_orders << std::endl; // would show can_move|can_fire std::cout << ~allowed_orders << std::endl; // would show can_patrol std::cout << orders::all << std::endl; // would show can_move|can_patrol|can_fire std::cout << ~orders::all << ' ' << orders::none << std::endl; // would show none none ( maybe? ) I'm not sure if a _COMMENTS version would be all that useful nor a _VALUES one. I'm also not sure whether the '|' character should be configurable. I'll stop thinking now before I come up with an enum_mask_iterator idea and make this far too complicated :P - Scott

Very nice looking library =)
Thanks! One addition I'd like to see would be a BOOST_ENUM_MASKS or similar:
BOOST_ENUM_MASKS( orders, (can_move) (can_patrol) (can_fire) )
I really like this idea. Want to help me implement it? Sounds like we need a bunch of operator overloads to make it all go. I've always wanted this sort of thing too. I'm not sure if a _COMMENTS version would be all that useful nor a
_VALUES one.
I'm now thinking of just having something else called a BOOST_STRINGTABLE, a convienent way to get at a bunch of strings without needing an external resource file/compiler. I'm also not sure whether the '|' character should be
configurable. I'll stop thinking now before I come up with an enum_mask_iterator idea and make this far too complicated :P
Hehe, it's sometimes hard to resist the urge to over-engineer, especially as a library developer eh? Although I am intriged about this iterator idea. -Frank
participants (9)
-
Frank Laub
-
Jason Hise
-
Larry Evans
-
Martin Bonner
-
me22
-
Paul Mensonides
-
Sebastian Redl
-
Thorsten Ottosen
-
Yuval Ronen