Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ scoped enums that are implicitly convertable to integers

Tags:

c++

enums

I have a question about the different forms of enums and enum class's, specifically to specify a large number of (scoped!) constants.

I was wondering if there is a way to declare a scoped enum, which is implicitly convertable to an integer. A usecase for this would be to specify register adresses and to be able to access them with something like MY_REGISTERS::FOO.

Here are the options that I know of and have encountered, please imagine a function with the signature void do_something(uint32_t bla) exists.

1: enum class

Enum class is scoped, but not implicitly convertable to an integer. I find it important that I don't have to static_cast it to an integer so this doesn't seem like the right fit.

enum class Foo : uint32_t
{
    BAR = 0x0000,
    BAZ = 0x0001
};

do_something(Foo::BAR) // Illegal, I'd have to `static_cast` here

2: enum

A regular C styled enum is implicitly convertable to an integer, but is not scoped (and pollutes the namespace it's in). Here is an example of why I find this undesirable for my usecase:

enum Foo : uint32_t
{
    BAR = 0x0000,
    BAZ = 0x0001
}

do_something(Foo::BAR) // Legal, and what I am looking for
do_something(BAR)      // Legal, whilst I don't want this to be possible

3: namespaced enum

This works, but if I encountered this somewhere, I'd raise an eyebrow. Something tells me there may be a better way

namespace Foo
{
    enum dontcare : uint32_t
    {
        BAR = 0x0000,
        BAZ = 0x0001
    };
}

do_something(Foo::BAR) // Legal, and what I am looking for
do_something(BAR)      // Illegal, just like I want it to be

4: namespaced static constexpr

Although this does what I want, I again (just like with the namespaced enum) feel like there must be a better way.

namespace Foo
{
    static constexpr uint32_t BAR = 0x0000,
    static constexpr uint32_t BAZ = 0x0001
}

do_something(Foo::BAR) // Legal, and what I am looking for
do_something(BAR)      // Illegal, just like I want it to be

So, all in all, is there a better way for this or will I have to stick to either namespaced enums or namespaced constexprs?

like image 640
McMuffinton Avatar asked Sep 25 '17 14:09

McMuffinton


People also ask

Can you cast an enum class to int?

Strongly typed enums can NOT be converted to integers without an explicit cast. Weak enums can, however, as they will be automatically implicitly cast. So, if you'd like automatic implicit conversion to an int, consider using a C-style weak enum instead (see more on this in the "Going further" section below).

What is a scoped enum?

Overview. Scoped enums (enum class/struct) are strongly typed enumerations introduced in C++11. They address several shortcomings of the old C-style (C++98) enums, mainly associated with type-safety and name collisions.

What is a strongly-typed enum?

The strongly-typed enumerations have to follow stronger rules: The enumerators can only be accessed in the scope of the enumeration. The enumerators don't implicitly convert to int. The enumerators aren't imported in the enclosing scope. The type of the enumerators is by default int.

What is CPP enumeration?

In C++ programming, enum or enumeration is a data type consisting of named values like elements, members, etc., that represent integral constants. It provides a way to define and group integral constants.


1 Answers

You can hack your own scoped enum by mixing a struct with a nested anonymous enum (Edit: I guess the enum itself doesn't have to be anonymous):

struct Foo{
    enum: uint32_t
    {
        BAR = 0x0000,
        BAZ = 0x0001
    };
};

Live Demo

It's not a scoped enum as per C++11 semantics ([dcl.enum]), but it's at least an enum that is scoped to the Foo class. And it's usable like how you want without polluting the global namespace:

do_something(Foo::BAR);
like image 84
AndyG Avatar answered Oct 18 '22 18:10

AndyG