Boost logo

Boost :

Subject: Re: [boost] [C++0x] Emulation of scoped enums
From: Daniel James (daniel_james_at_[hidden])
Date: 2009-03-08 04:21:39


2009/3/7 Matt Calabrese <rivorus_at_[hidden]>:
>
> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk