Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 metaprogramming - lookup enum value during compilation (values contains gaps)

Is there a way, at compile-time, to verify that a given value is within the values of a given enum, thus valid?

enum myenum { val1 = 10, val2 = 30, val3 = 45 }

template <myenum t>
class myClass
{ ... }

myClass<10> a; // fails, OK
myClass<val1> b; // compiles OK
myClass<myenum(24)> c; //compiles, NOT OK!

Using a second template non-type boolean parameter would be useful in there, and the value of that boolean would be given by a meta-function, that given a value would verify that the value is within the values of myenum.

I looked through various enum related question, like how to iterate an enum, and it seems it can't be done.

like image 798
emitrax Avatar asked Jun 22 '12 19:06

emitrax


People also ask

How do I convert an enum to a string in C ++?

The stringify() macro method is used to convert an enum into a string. Variable dereferencing and macro replacements are not necessary with this method. The important thing is that, only the text included in parenthesis may be converted using the stringify() method.

How do enums work in C++?

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. It also makes the code easy to maintain and less complex.

How are enumeration variables declared?

An enumeration type declaration gives the name of the (optional) enumeration tag. And, it defines the set of named integer identifiers (called the enumeration set, enumerator constants, enumerators, or members). A variable of the enumeration type stores one of the values of the enumeration set defined by that type.

Is enum class C++?

C++11 has introduced enum classes (also called scoped enumerations), that makes enumerations both strongly typed and strongly scoped. Class enum doesn't allow implicit conversion to int, and also doesn't compare enumerators from different enumerations. To define enum class we use class keyword after enum keyword.


2 Answers

enum myenum { val1 = 10, val2 = 30, val3 = 45 };
template<myenum e> struct is_valid_myenum { static const bool value = (e==val1 || e==val2 || e==val3); };

template<myenum t>
class myClass
{
    static_assert(is_valid_myenum<t>::value, "t must be a valid enum value");
};

myClass<10> a; // fails, OK
myClass<val1> b; // compiles OK
myClass<myenum(24)> c; // fails, OK

If you really, really want to avoid the duplication (and aren't interested in using some external tool to generate sourcecode) you can resort to macro hackery.

#define LIST \
    ITEM(val1,10)\
    ITEM(val2,30)\
    ITEM(val3,45)

#define ITEM(NAME,VALUE) NAME = VALUE,

enum myenum { LIST };

#undef ITEM

#define ITEM(NAME,VALUE) e==NAME ||

template<myenum e> struct is_valid_myenum { static const bool value = ( LIST false ); };

template<myenum t>
class myClass
{
    static_assert(is_valid_myenum<t>::value, "t must be a valid enum value");
};

myClass<10> a; // fails, OK
myClass<val1> b; // compiles OK
myClass<myenum(24)> c; // fails, OK
like image 134
bames53 Avatar answered Sep 28 '22 05:09

bames53


You can never prevent other developers to shoot in their own foot. You can never win. Just ensure your API does not make it easy.

If he takes an invalid value, casts it, and then passes it to you, it is purely his problem. This is the same kind of problem as if you provide him a function taking a pointer of type T* as parameter, but he takes some random data (of arbitrary type), casts it to T* and passes it in.

That's how casting works: The person who does the cast is responsible to guarantee that the casted expression can be safely interpreted as value of the type he casts to.

like image 22
mity Avatar answered Sep 28 '22 07:09

mity