
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