explicit conversion from enum class to its underlying type

1,466 views
Skip to first unread message

Andrzej Krzemieński

unread,
Oct 29, 2016, 5:51:12 PM10/29/16
to ISO C++ Standard - Future Proposals
Hi All,

One of the nice safety features of enum classes is that they cannot be implicitly converted to their underlying type. However, do you think we would lose this safety feature if we allowed an explicit conversion to the underlying type?

I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

It would be beneficial to have a unique Boolean type that would not be convertible to another unique Boolean type. One solution is to use an enum class with `bool` as underlying type:

enum class SkipUnused : bool { No, Yes };
enum class SkipNeative : bool { No, Yes };

void process(SkipUnused skipUnused)
{
 
if (skipUnused) // doesn't compile
   
{}
}

Unfortunately, such enum-based type does not work with boolean expressions. It would we had an explicit conversion.

Do you think, it would be acceptable to add such explicit conversion to the underlying type, for enum classes?

Regards,
&rzej;

Tim

unread,
Oct 29, 2016, 7:55:09 PM10/29/16
to ISO C++ Standard - Future Proposals
We already have explicit conversions for scoped enums (they aren't pretty, though)

#include <type_traits>

enum class SkipUnused : bool {No, Yes};

void process(SkipUnused skipUnused) {
if (static_cast<std::underlying_type<SkipUnused>::type>(skipUnused)){}

Nicol Bolas

unread,
Oct 29, 2016, 8:31:16 PM10/29/16
to ISO C++ Standard - Future Proposals
On Saturday, October 29, 2016 at 5:51:12 PM UTC-4, Andrzej Krzemieński wrote:
Hi All,

One of the nice safety features of enum classes is that they cannot be implicitly converted to their underlying type. However, do you think we would lose this safety feature if we allowed an explicit conversion to the underlying type?

I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

So, what you're asking for is if the underlying type of a strong enum is `bool`, then that type can be contextually converted to `bool`. I don't think it's worth adding a language feature for such an incredibly narrow corner case.

Daniel Frey

unread,
Oct 29, 2016, 8:40:22 PM10/29/16
to std-pr...@isocpp.org
> On 29 Oct 2016, at 23:51, Andrzej Krzemieński <akrz...@gmail.com> wrote:
>
> I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

If all you need is boolean conversion, how about

template<typename E>
constexpr std::enable_if_t<std::is_enum_v<E>,bool> is(E e) noexcept
{
return e == E(true);
}

to be used like

if(is(skipUnused)) { ... }

Instead of is(), you could also use operators, e.g.

+skipUnused

or

!skipUnused

(the latter might actually be sensible, but inconsistent if skipUnused itself is not convertible to bool)

There is a caveat with using boolean enums, i.e., if the user writes:

enum class SkipUnused { Yes, No };

(Note the order of the values).

There is no way for us to detect this, unless we explicitly would expect a value called Yes (or should it be YES or TRUE?) and change the above to

template<typename E>
constexpr std::enable_if_t<std::is_enum_v<E>,bool> is(E e) noexcept
{
return e == E::Yes;
}

> Do you think, it would be acceptable to add such explicit conversion to the underlying type, for enum classes?

If anything, it should be explicit for a type, not implicit for all enums. Maybe allowing something like:

enum class SkipUnused { No, Yes };
explicit constexpr SkipUnused::operator bool() = default;

or

explicit constexpr SkipUnused::operator bool() noexcept { return *this == Yes; }

where *this refers to the enum value and Yes is in the scope of SkipUnused, hence no SkipUnused::Yes is needed. Something like a "member" of an enum class. This might also allow other conversions (explicitly), making a possible proposal usable in more contexts. I'm not really sure it is worth it, though.

Vicente J. Botet Escriba

unread,
Oct 30, 2016, 3:50:18 AM10/30/16
to std-pr...@isocpp.org
Le 29/10/2016 à 23:51, Andrzej Krzemieński a écrit :
Hi All,

One of the nice safety features of enum classes is that they cannot be implicitly converted to their underlying type. However, do you think we would lose this safety feature if we allowed an explicit conversion to the underlying type?

I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

This works already in a non-contextual conversion, isn't it?

    bool(e)

I believe the missing contextual conversion merits an issue.

BTW, Boost.ScopedEnum emulation defined an explicit conversion on compilers with them and without enum class.


It would be beneficial to have a unique Boolean type that would not be convertible to another unique Boolean type. One solution is to use an enum class with `bool` as underlying type:

enum class SkipUnused : bool { No, Yes };
enum class SkipNeative : bool { No, Yes };

void process(SkipUnused skipUnused)
{
 
if (skipUnused) // doesn't compile
   
{}
}

Unfortunately, such enum-based type does not work with boolean expressions. It would we had an explicit conversion.
Well, this is a common problem due to the fact we are missing strongly(opaque) types.




Do you think, it would be acceptable to add such explicit conversion to the underlying type, for enum classes?
Given that the explicit cast to the underlying type works already, I believe it is a reasonable feature, and I don't know what could be the reason to don't define it. Maybe some know it.

        SkipUnused e{};
        if (bool(e))
            std::cout << "Yes\n";
        else
            std::cout << "No\n";

When we want to be explicit without naming the type I would add a function, but this is not your case.

template <typename E>
auto underlying(E e)  { return static_cast<underlying_type_t<E>>(e); }

auto x = underlying(e);

Vicente

Zhihao Yuan

unread,
Oct 30, 2016, 4:32:39 AM10/30/16
to std-pr...@isocpp.org
On Sun, Oct 30, 2016 at 2:50 AM, Vicente J. Botet Escriba
<vicent...@wanadoo.fr> wrote:
>
> This works already in a non-contextual conversion, isn't it?
>
> bool(e)
>
> I believe the missing contextual conversion merits an issue.

I feel the same. At least this specific use case should work.

Currently contextually converted to bool requires direct
initialization from bool:

bool t(e);

I don't know of a case other than scoped enum where
explicit conversion to bool is supported but not
initialization, so maybe we could just fix contextually converted
to bool by querying for `bool(e)`.

Fixing scoped enum is a little bit more concerning
to me.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://blog.miator.net/

Nicol Bolas

unread,
Oct 30, 2016, 8:20:40 AM10/30/16
to ISO C++ Standard - Future Proposals


On Sunday, October 30, 2016 at 3:50:18 AM UTC-4, Vicente J. Botet Escriba wrote:
Le 29/10/2016 à 23:51, Andrzej Krzemieński a écrit :
Hi All,

One of the nice safety features of enum classes is that they cannot be implicitly converted to their underlying type. However, do you think we would lose this safety feature if we allowed an explicit conversion to the underlying type?

I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

This works already in a non-contextual conversion, isn't it?

    bool(e)

No, it doesn't. The only way to convert a strongly typed enum to its underlying type is with a `static_cast`.

Vicente J. Botet Escriba

unread,
Oct 30, 2016, 9:53:41 AM10/30/16
to std-pr...@isocpp.org


enum class SkipUnused : bool { No, Yes };

        SkipUnused e{};
        bool b1 {bool(e)}; (void)b1;
        bool b2 =bool(e); (void)b2;
        b1 = bool(e);

        if (bool(e))
            std::cout << "Yes\n";
        else
            std::cout << "No\n";

Maybe there is a bug in both compilers ;-)

Vicente

Nicol Bolas

unread,
Oct 30, 2016, 10:23:08 AM10/30/16
to ISO C++ Standard - Future Proposals
On Sunday, October 30, 2016 at 9:53:41 AM UTC-4, Vicente J. Botet Escriba wrote:
Le 30/10/2016 à 13:20, Nicol Bolas a écrit :


On Sunday, October 30, 2016 at 3:50:18 AM UTC-4, Vicente J. Botet Escriba wrote:
Le 29/10/2016 à 23:51, Andrzej Krzemieński a écrit :
Hi All,

One of the nice safety features of enum classes is that they cannot be implicitly converted to their underlying type. However, do you think we would lose this safety feature if we allowed an explicit conversion to the underlying type?

I do not know of any practical use of explicit conversion operators except for the contextual conversion to bool. And it is only this conversion that I am interested in.

This works already in a non-contextual conversion, isn't it?

    bool(e)

No, it doesn't. The only way to convert a strongly typed enum to its underlying type is with a `static_cast`.

It works for clang and gcc

So why doesn't it work when you use direct initialization of a variable (like `bool b{e}`)? Direct initialization and creating a temporary ought to work identically.

So if this is an issue, then I would say that the issue is the asymmetry between direct initialization of enum classes and creating prvalues of them.

Peter Koch Larsen

unread,
Oct 30, 2016, 10:33:15 AM10/30/16
to std-pr...@isocpp.org
I believe bool(e) in that context was a C-style cast.

A small helper function would in my opinion be the best way out for
this purpose.

/Peter
> --
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/74d02121-9633-b6d1-1187-2a9ab660089d%40wanadoo.fr.

Andrzej Krzemienski

unread,
Oct 31, 2016, 4:15:04 AM10/31/16
to std-pr...@isocpp.org
But are you saying that the process of pushing this change into the language is too expensive to warrant the satisfaction of a marginal use case? Or are you saying that satisfying one small use case is over-weighed by potential type safety hole that would come with the change?

Regards,
&rzej;

Reply all
Reply to author
Forward
0 new messages