Is there a way to specify the default constructor of an enum class?
I am using an enum class to specify a set of values which are allowable for a particular datatype in a library: in this case, it's the GPIO pin id numbers of a Raspberry Pi. It looks something like this:
enum class PinID : int {N4 = 4, N17 = 17, /* ...etc... */ }
The point of me doing this instead just of using, say, an int is to ensure that code is safe: I can static_assert (or otherwise compile-time ensure -- the actual method used is not important to me) things like that someone hasn't made a spelling error (passing a 5 instead of a 4, etc), and I get automatic error messages for type mismatches, etc.
The problem then is that enum class has a default constructor that -- for compatibility's sake with C's enums I assume (since they have the same behaviour) -- initializes to the enum class equivalent of 0. In this case, there is no 0 value. This means that a user making a declaration/definition like:
PinID pid = PinID();
is getting an enumerator that isn't explicitly defined (and doesn't even seem to "exist" when one looks at the code), and can lead to runtime errors. This also means that techniques like switching over the values of explicitly defined enumerators is impossible without having an error/default case -- something I want to avoid, since it forces me to either throw or do something like return a boost::optional, which are less amenable to static analysis.
I tried to define a default constructor to no avail. I (desperately) tried to define a function which shares the name of the enum class, but this (rather unsurprisingly) resulted in strange compiler errors. I want to retain the ability to cast the enum class to int, with all N# enumerators mapping to their respective #, so merely "defining", say, N4 = 0 is unacceptable; this is for simplicity and sanity.
I guess my question is two-fold: is there a way to get the kind of static safety I'm after using enum class? If not, what other possibilities would one prefer? What I want is something which:
is default constructable
can be made to default construct to an arbitrary valid value
provides the "finite set of specified" values afforded by enum classes
is at least as type safe as an enum class
(preferably) doesn't involve runtime polymorphism
The reason I want default constructability is because I plan to use boost::lexical_cast to reduce the syntactic overhead involved in conversions between the enum class values, and the actual associated strings which I output to the operating system (sysfs in this case); boost::lexical_cast requires default constructability.
Errors in my reasoning are welcome -- I am beginning to suspect that enum classes are the right object for the wrong job, in this case; clarification will be offered if asked. Thank you for your time.
A type defined with enum class or enum struct is not a a class but a scoped enumeration and can not have a default constructor defined. The C++11 standard defines that your PinID pid = PinID(); statement will give a zero-initialization. Where PinID was defined as a enum class. It also allows enum types in general to hold values other than the enumerator constants.
To understand that PinID() gives zero initialization requires reading standard sections 3.9.9, 8.5.5, 8.5.7 and 8.5.10 together:
8.5.10 - An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized
8.5.7 - To value-initialize an object of type T means: ... otherwise, the object is zero-initialized.
8.5.5 - To zero-initialize an object or reference of type T means: — if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
3.9.9 - States that enumeration types are part of the set of types known as scalar types.
A possible solution:
To meet your points 1 to 5 you could write a class along the lines of:
class PinID
{
private:
PinID(int val)
: m_value(val)
{}
int m_value;
public:
static const PinID N4;
static const PinID N17;
/* ...etc... */
PinID()
: m_value(N4.getValue())
{}
PinID(const PinID &id)
: m_value(id.getValue())
{}
PinID &operator = (const PinID &rhs)
{
m_value = rhs.getValue();
return *this;
}
int getValue() const
{
return m_value;
}
// Attempts to create from int and throw on failure.
static PinID createFromInt(int i);
friend std::istream& operator>>(std::istream &is, PinID &v)
{
int candidateVal(0);
is >> candidateVal;
v = PinID::createFromInt(candidateVal);
return is;
}
};
const PinID PinID::N4 = PinID(4);
/* ...etc... */
That can give you something that you would have to make specific efforts to get an invalid values into. The default constructor and stream operator should allow it to work with lexical_cast.
Seems it depends how critical the operations on a PinID are after it's creation whether it's worth writing a class or just handling the invalid values everywhere as the value is used.
An enum class is just a strongly-typed enum; it's not a class. C++11 just reused the existing class keyword to avoid introducing a new keyword that would break compatibility with legacy C++ code.
As for your question, there is no way to ensure at compile time that a cast involves a proper candidate. Consider:
int x;
std::cin >> x;
auto p = static_cast<PinID>(x);
This is perfectly legal and there is no way to statically ensure the console user has done the right thing.
Instead, you will need to check at runtime that the value is valid. To get around this in an automated fashion, one of my co-workers created an enum generator that builds these checks plus other helpful routines given a file with enumeration values. You will need to find a solution that works for you.
I know that this question is dated and that it already has an accepted answer but here is a technique that might help in a situation like this with some of the newer features of C++
You can declare this class's variable either non static or static, it can be done in several ways permitted on support of your current compiler.
Non Static:
#include <iostream>
#include <array>
template<unsigned... IDs>
class PinIDs {
private:
const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
Static: - There are 3 ways to write this: (First One - C++11 or 14 or higher) last 2 (c++17).
Don't quote me on the C++11 part; I'm not quite sure when variadic templates or parameter packs were first introduced.
template<unsigned... IDs>
class PinIDs{
private:
static const std::array<unsigned, sizeof...(IDs)> ids;
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
const std::array<unsigned, sizeof...(IDs)> PinIDs<IDs...>::ids { IDs... };
template<unsigned... IDs>
class PinIDs{
private:
static constexpr std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
class PinIDs{
private:
static inline const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
All examples above either non-static or static work with the same use case below and provide the correct results:
int main() {
PinIDs<4, 17, 19> myId;
std::cout << myId[0] << " ";
std::cout << myId[1] << " ";
std::cout << myId[2] << " ";
std::cout << "\nPress any key and enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
Output
4 17 19
Press any key and enter to quit.
With this type of class template using a variadic parameter list, you don't have to use any constructor but the default. I did add bounds checking into the array so that the operator[] doesn't exceed bounds of its size; I could of threw an error but with unsigned type I just simply returned -1 as an invalid value.
With this type, there is no default as you have to instantiate this kind of object via template parameter list with a single or set of values. If one wants to they can specialize this class with a single parameter of 0 for a default type. When you instantiate this type of object; it is final as in it can not be changed from its declaration. This is a const object and still holds to be default constructible.
Related
Is there a way to specify the default constructor of an enum class?
I am using an enum class to specify a set of values which are allowable for a particular datatype in a library: in this case, it's the GPIO pin id numbers of a Raspberry Pi. It looks something like this:
enum class PinID : int {N4 = 4, N17 = 17, /* ...etc... */ }
The point of me doing this instead just of using, say, an int is to ensure that code is safe: I can static_assert (or otherwise compile-time ensure -- the actual method used is not important to me) things like that someone hasn't made a spelling error (passing a 5 instead of a 4, etc), and I get automatic error messages for type mismatches, etc.
The problem then is that enum class has a default constructor that -- for compatibility's sake with C's enums I assume (since they have the same behaviour) -- initializes to the enum class equivalent of 0. In this case, there is no 0 value. This means that a user making a declaration/definition like:
PinID pid = PinID();
is getting an enumerator that isn't explicitly defined (and doesn't even seem to "exist" when one looks at the code), and can lead to runtime errors. This also means that techniques like switching over the values of explicitly defined enumerators is impossible without having an error/default case -- something I want to avoid, since it forces me to either throw or do something like return a boost::optional, which are less amenable to static analysis.
I tried to define a default constructor to no avail. I (desperately) tried to define a function which shares the name of the enum class, but this (rather unsurprisingly) resulted in strange compiler errors. I want to retain the ability to cast the enum class to int, with all N# enumerators mapping to their respective #, so merely "defining", say, N4 = 0 is unacceptable; this is for simplicity and sanity.
I guess my question is two-fold: is there a way to get the kind of static safety I'm after using enum class? If not, what other possibilities would one prefer? What I want is something which:
is default constructable
can be made to default construct to an arbitrary valid value
provides the "finite set of specified" values afforded by enum classes
is at least as type safe as an enum class
(preferably) doesn't involve runtime polymorphism
The reason I want default constructability is because I plan to use boost::lexical_cast to reduce the syntactic overhead involved in conversions between the enum class values, and the actual associated strings which I output to the operating system (sysfs in this case); boost::lexical_cast requires default constructability.
Errors in my reasoning are welcome -- I am beginning to suspect that enum classes are the right object for the wrong job, in this case; clarification will be offered if asked. Thank you for your time.
A type defined with enum class or enum struct is not a a class but a scoped enumeration and can not have a default constructor defined. The C++11 standard defines that your PinID pid = PinID(); statement will give a zero-initialization. Where PinID was defined as a enum class. It also allows enum types in general to hold values other than the enumerator constants.
To understand that PinID() gives zero initialization requires reading standard sections 3.9.9, 8.5.5, 8.5.7 and 8.5.10 together:
8.5.10 - An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized
8.5.7 - To value-initialize an object of type T means: ... otherwise, the object is zero-initialized.
8.5.5 - To zero-initialize an object or reference of type T means: — if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
3.9.9 - States that enumeration types are part of the set of types known as scalar types.
A possible solution:
To meet your points 1 to 5 you could write a class along the lines of:
class PinID
{
private:
PinID(int val)
: m_value(val)
{}
int m_value;
public:
static const PinID N4;
static const PinID N17;
/* ...etc... */
PinID()
: m_value(N4.getValue())
{}
PinID(const PinID &id)
: m_value(id.getValue())
{}
PinID &operator = (const PinID &rhs)
{
m_value = rhs.getValue();
return *this;
}
int getValue() const
{
return m_value;
}
// Attempts to create from int and throw on failure.
static PinID createFromInt(int i);
friend std::istream& operator>>(std::istream &is, PinID &v)
{
int candidateVal(0);
is >> candidateVal;
v = PinID::createFromInt(candidateVal);
return is;
}
};
const PinID PinID::N4 = PinID(4);
/* ...etc... */
That can give you something that you would have to make specific efforts to get an invalid values into. The default constructor and stream operator should allow it to work with lexical_cast.
Seems it depends how critical the operations on a PinID are after it's creation whether it's worth writing a class or just handling the invalid values everywhere as the value is used.
An enum class is just a strongly-typed enum; it's not a class. C++11 just reused the existing class keyword to avoid introducing a new keyword that would break compatibility with legacy C++ code.
As for your question, there is no way to ensure at compile time that a cast involves a proper candidate. Consider:
int x;
std::cin >> x;
auto p = static_cast<PinID>(x);
This is perfectly legal and there is no way to statically ensure the console user has done the right thing.
Instead, you will need to check at runtime that the value is valid. To get around this in an automated fashion, one of my co-workers created an enum generator that builds these checks plus other helpful routines given a file with enumeration values. You will need to find a solution that works for you.
I know that this question is dated and that it already has an accepted answer but here is a technique that might help in a situation like this with some of the newer features of C++
You can declare this class's variable either non static or static, it can be done in several ways permitted on support of your current compiler.
Non Static:
#include <iostream>
#include <array>
template<unsigned... IDs>
class PinIDs {
private:
const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
Static: - There are 3 ways to write this: (First One - C++11 or 14 or higher) last 2 (c++17).
Don't quote me on the C++11 part; I'm not quite sure when variadic templates or parameter packs were first introduced.
template<unsigned... IDs>
class PinIDs{
private:
static const std::array<unsigned, sizeof...(IDs)> ids;
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
const std::array<unsigned, sizeof...(IDs)> PinIDs<IDs...>::ids { IDs... };
template<unsigned... IDs>
class PinIDs{
private:
static constexpr std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
class PinIDs{
private:
static inline const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
All examples above either non-static or static work with the same use case below and provide the correct results:
int main() {
PinIDs<4, 17, 19> myId;
std::cout << myId[0] << " ";
std::cout << myId[1] << " ";
std::cout << myId[2] << " ";
std::cout << "\nPress any key and enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
Output
4 17 19
Press any key and enter to quit.
With this type of class template using a variadic parameter list, you don't have to use any constructor but the default. I did add bounds checking into the array so that the operator[] doesn't exceed bounds of its size; I could of threw an error but with unsigned type I just simply returned -1 as an invalid value.
With this type, there is no default as you have to instantiate this kind of object via template parameter list with a single or set of values. If one wants to they can specialize this class with a single parameter of 0 for a default type. When you instantiate this type of object; it is final as in it can not be changed from its declaration. This is a const object and still holds to be default constructible.
This is certainly related to a bunch of other questions which have been answered, but I have been unable to derive the answer for my specific case from them, largely because I'm not actually a programmer; I'm just an engineer who happens to have to write some code.
Here's the situation:
I have a bunch of variables I'd like to collect together, probably into a structure.
All but two I would like to initialize to zero; two specific variables (which don't happen to be the first two) need to be initialized to one.
The actual names are unique and meaningful enough that using a vector wouldn't be appropriate, plus there are some doubles in there too. I'm keeping my example below simple for clarity.
Because of the project I'm working on, I'm stuck with C++98, so even if C++11 has more elegant solutions, they won't work for me.
I am thinking something along these lines for the structure itself:
struct allFlags
{
int flagAA;
int flagAB;
int flagAC;
int flagAD;
int flagAE;
// ...
// there's about 100 variables total
// ...
int flagZZ;
};
I want to have all the flags initialized to 0 except for flagAD and flagAE, which should be 1.
So first of all, I am not sure if I should use typedef struct allFlags or struct allFlags. Next, I am not sure if I should be creating a constructor (which I think only would apply in the case of no typedef?) or making the defaults happens when I instantiate the structure. I have seen things like this (which would be put inside the struct definition):
allFlags() : flagAD(1), flagAE(1) { /*not sure of I'd need anything here*/ }
but I wouldn't want to have to list out all other ~98 variables by name individually in the constructor body to set them to zero. I have also seen things using memset which could potentially help, but I'm not sure the best way to do it.
And finally one additional related question is how to actually declare an instance of my structure (which results in the initial values I want). It looks like sometimes a struct is instantiated with the new keyword and sometimes is it treated more like a base data type, i.e. I have seen both of these in searching:
allFlags flagset1;
flagset2 = new allFlags;
I have also seen syntax which would be like this rather than using a constructor at all:
allFlags flagset3 = {}; // to zero all fields first
flagset3.flagAD = 1;
flagset3.flagAE = 1;
but I'd rather keep the instantiation as clean and simple as possible.
Please forgive the question. I have tried to do my homework before asking, but my C++ knowledge is mediocre at best and so some of the seemingly relevant answers I've found I either didn't fully understand or just raised more questions.
If you feel comfortable with using templates, you can use a class template to automate clean initialization of all member variables of allFlags.
// class template to help initialize members cleanly.
template <typename T>
struct flag
{
// Constructors
flag() : val(0) {}
flag(T const& v) : val(v) {}
// Automatic cast operators to T
operator T& () { return val; }
operator T const& () const { return val; }
// Comparison operators
bool operator==(flag const& rhs) const { return val == rhs.val; }
bool operator!=(flag const& rhs) const { return val != rhs.val; }
bool operator<(flag const& rhs) const { return val < rhs.val; }
T val;
};
typedef flag<int> IntFlag;
typedef flag<double> DoubleFlag;
struct allFlags
{
// Initialize all flags bug flagAD to zero.
allFlags() : flagAD(1) {}
IntFlag flagAA;
IntFlag flagAB;
IntFlag flagAC;
IntFlag flagAD;
IntFlag flagAE;
IntFlag flagZZ;
};
#include <iostream>
int main()
{
allFlags f;
std::cout << f.flagAA << " " << f.flagAD << std::endl;
}
Output:
0 1
You answered your own question quite well:
allFlags flagset3 = {}; // to zero all fields first
flagset3.flagAD = 1;
flagset3.flagAE = 1;
It is clean, and very clear about your intentions. Later, when someone else has to read your code they will understand exactly what you are trying to do.
It is similar to what you see in device driver programming:
registerX = 0 | 1 << BIT2 | 1 << BIT3;
Lately I'm writing my getter and setters as (note: real classes do more things in getter/setter):
struct A {
const int& value() const { return value_; } // getter
int& value() { return value_; } // getter/setter
private:
int value_;
};
which allows me to do the following:
auto a = A{2}; // non-const object a
// create copies by "default" (value always returns a ref!):
int b = a.value(); // b = 2, is a copy of value :)
auto c = a.value(); // c = 2, is a copy of value :)
// create references explicitly:
auto& d = a.value(); // d is a ref to a.value_ :)
decltype(a.value()) e = a.value(); // e is a ref to a.value_ :)
a.value() = 3; // sets a.value_ = 3 :)
cout << b << " " << c << " " << d << " " << e << endl; // 2 2 3 3
const auto ca = A{1};
const auto& f = ca.value(); // f is a const ref to ca.value_ :)
auto& g = ca.value(); // no compiler error! :(
// g = 4; // compiler error :)
decltype(ca.value()) h = ca.value(); // h is a const ref to ca.value_ :)
//ca.value() = 2; // compiler error! :)
cout << f << " " << g << " " << h << endl; // 1 1 1
This approach doesn't allow me to:
validate the input for the setter (which is a big BUT),
return by value in the const member function (because I want the compiler to catch assignment to const objects: ca.value() = 2). Update: see cluracan answer below.
However, I'm still using this a lot because
most of the time I don't need that,
this allows me to decouple the implementation details of my classes from their interface, which is just what I want.
Example:
struct A {
const int& value(const std::size_t i) const { return values_[i]; }
int& value(const std::size_t i) { return values_[i]; }
private:
std::vector<int> values_;
// Storing the values in a vector/list/etc is an implementation detail.
// - I can validate the index, but not the value :(
// - I can change the type of values, without affecting clients :)
};
Now to the questions:
Are there any other disadvantages of this approach that I'm failing to see?
Why do people prefer:
getter/setters methods with different names?
passing the value as a parameter?
just for validating input or are there any other main reasons?
Generally using accessors/mutators at all is a design smell that your class public interface is incomplete. Typically speaking you want a useful public interface that provides meaningful functionality rather than simply get/set (which is just one or two steps better than we were in C with structs and functions). Every time you want to write a mutator, and many times you want to write an accessor first just take a step back and ask yourself "do I *really* need this?".
Just idiom-wise people may not be prepared to expect such a function so it will increase a maintainer's time to grok your code.
The same-named methods are almost the same as the public member: just use a public member in that case. When the methods do two different things, name them two different things.
The "mutator" returning by non-const reference would allow for a wide variety of aliasing problems where someone stashes off an alias to the member, relying on it to exist later. By using a separate setter function you prevent people from aliasing to your private data.
This approach doesn't allow me to:
return by value in the const member function (because I want the compiler to catch assignment to const objects ca.value() = 2).
I don't get what you mean. If you mean what I think you mean - you're going to be pleasantly surprised :) Just try to have the const member return by value and see if you can do ca.value()=2...
But my main question, if you want some kind of input validation, why not use a dedicated setter and a dedicated getter
struct A {
int value() const { return value_; } // getter
void value(int v) { value_=v; } // setter
private:
int value_;
};
It will even reduce the amount typing! (by one '=') when you set. The only downside to this is that you can't pass the value by reference to a function that modifies it.
Regarding your second example after the edit, with the vector - using your getter/setter makes even more sense than your original example as you want to give access to the values (allow the user to change the values) but NOT to the vector (you don't want the user to be able to change the size of the vector).
So even though in the first example I really would recommend making the member public, in the second one it is clearly not an option, and using this form of getters / setters really is a good option if no input validation is needed.
Also, when I have classes like your second type (with the vector) I like giving access to the begin and end iterators. This allows more flexibility of using the data with standard tools (while still not allowing the user to change the vector size, and allowing easy change in container type)
Another bonus to this is that random access iterators have an operator[] (like pointers) so you can do
vector<int>::iterator A::value_begin() {return values_.begin();}
vector<int>::const_iterator A::value_begin()const{return values_.begin();}
...
a.value_begin()[252]=3;
int b=a.value_begin()[4];
vector<int> c(a.value_begin(),a.value_end())
(although it maybe ugly enough that you'd still want your getters/setters in addition to this)
REGARDING INPUT VALIDATION:
In your example, the assignment happens in the calling code. If you want to validate user input, you need to pass the value to be validated into your struct object. This means you need to use member functions (methods). For example,
struct A {
// getter
int& getValue() const { return value_; }
// setter
void setValue(const int& value) {
// validate value here
value_ = value;
}
private:
int value_;
};
By the way, .NET properties are implemented are methods under the hood.
It is common knowledge that built-in enums in C++ are not typesafe.
I was wondering which classes implementing typesafe enums are used out there...
I myself use the following "bicycle", but it is somewhat verbose and limited:
typesafeenum.h:
struct TypesafeEnum
{
// Construction:
public:
TypesafeEnum(): id (next_id++), name("") {}
TypesafeEnum(const std::string& n): id(next_id++), name(n) {}
// Operations:
public:
bool operator == (const TypesafeEnum& right) const;
bool operator != (const TypesafeEnum& right) const;
bool operator < (const TypesafeEnum& right) const;
std::string to_string() const { return name; }
// Implementation:
private:
static int next_id;
int id;
std::string name;
};
typesafeenum.cpp:
int TypesafeEnum::next_id = 1;
bool TypesafeEnum::operator== (const TypesafeEnum& right) const
{ return id == right.id; }
bool TypesafeEnum::operator!= (const TypesafeEnum& right) const
{ return !operator== (right); }
bool TypesafeEnum::operator< (const TypesafeEnum& right) const
{ return id < right.id; }
Usage:
class Dialog
{
...
struct Result: public TypesafeEnum
{
static const Result CANCEL("Cancel");
static const Result OK("Ok");
};
Result doModal();
...
};
const Dialog::Result Dialog::Result::OK;
const Dialog::Result Dialog::Result::CANCEL;
Addition:
I think I should have been more specific about the requirements. I'll try to summarize them:
Priority 1: Setting an enum variable to an invalid value should be impossible (a compile-time error) with no exceptions.
Priority 2: Converting an enum value to/from an int should be possible with a single explicit function/method call.
Priority 3: As compact, elegant and convenient declaration and usage as possible
Priority 4: Converting enum values to and from strings.
Priority 5: (Nice to have) Possibility to iterate over enum values.
I'm currently playing around with the Boost.Enum proposal from the Boost Vault (filename enum_rev4.6.zip). Although it was never officially submitted for inclusion into Boost, it's useable as-is. (Documentation is lacking but is made up for by clear source code and good tests.)
Boost.Enum lets you declare an enum like this:
BOOST_ENUM_VALUES(Level, const char*,
(Abort)("unrecoverable problem")
(Error)("recoverable problem")
(Alert)("unexpected behavior")
(Info) ("expected behavior")
(Trace)("normal flow of execution")
(Debug)("detailed object state listings")
)
And have it automatically expand to this:
class Level : public boost::detail::enum_base<Level, string>
{
public:
enum domain
{
Abort,
Error,
Alert,
Info,
Trace,
Debug,
};
BOOST_STATIC_CONSTANT(index_type, size = 6);
Level() {}
Level(domain index) : boost::detail::enum_base<Level, string>(index) {}
typedef boost::optional<Level> optional;
static optional get_by_name(const char* str)
{
if(strcmp(str, "Abort") == 0) return optional(Abort);
if(strcmp(str, "Error") == 0) return optional(Error);
if(strcmp(str, "Alert") == 0) return optional(Alert);
if(strcmp(str, "Info") == 0) return optional(Info);
if(strcmp(str, "Trace") == 0) return optional(Trace);
if(strcmp(str, "Debug") == 0) return optional(Debug);
return optional();
}
private:
friend class boost::detail::enum_base<Level, string>;
static const char* names(domain index)
{
switch(index)
{
case Abort: return "Abort";
case Error: return "Error";
case Alert: return "Alert";
case Info: return "Info";
case Trace: return "Trace";
case Debug: return "Debug";
default: return NULL;
}
}
typedef boost::optional<value_type> optional_value;
static optional_value values(domain index)
{
switch(index)
{
case Abort: return optional_value("unrecoverable problem");
case Error: return optional_value("recoverable problem");
case Alert: return optional_value("unexpected behavior");
case Info: return optional_value("expected behavior");
case Trace: return optional_value("normal flow of execution");
case Debug: return optional_value("detailed object state listings");
default: return optional_value();
}
}
};
It satisfies all five of the priorities which you list.
A nice compromise method is this:
struct Flintstones {
enum E {
Fred,
Barney,
Wilma
};
};
Flintstones::E fred = Flintstones::Fred;
Flintstones::E barney = Flintstones::Barney;
It's not typesafe in the same sense that your version is, but the usage is nicer than standard enums, and you can still take advantage of integer conversion when you need it.
I use C++0x typesafe enums. I use some helper template/macros that provide the to/from string functionality.
enum class Result { Ok, Cancel};
I don't. Way too much overhead for little benefit. Also, being able to caste enumerations to different data types for serialization is a very handy tool. I have never seen an instance where a "Type safe" enumeration would be worth the overhead and complexity where C++ offers a good enough implementation already.
My take is that you're inventing a problem and then fitting a solution onto it. I see no need to do an elaborate framework for an enumeration of values. If you are dedicated to having your values only be members of a certain set, you could hack up a variant of a unique set datatype.
I'm personally using an adapted version of the typesafe enum idiom. It doesn't provide all the five "requirements" that you've stated in your edit, but I strongly disagree with some of them anyway. For example, I don't see how Prio#4 (conversion of values to strings) has anything to do with type safety. Most of the time string representation of individual values should be separate from the definition of the type anyway (think i18n for a simple reason why). Prio#5 (iteratio, which is optional) is one of the nicest things I'd like to see naturally happening in enums, so I felt sad that it appears as "optional" in your request, but it seems it is better addressed via a separate iteration system such as begin/end functions or an enum_iterator, which makes them work seamlessly with STL and C++11 foreach.
OTOH this simple idiom nicely provides Prio#3 Prio#1 thanks to the fact that it mostly only wraps enums with more type information. Not to mention it is a very simple solution that for the most part doesn't require any external dependency headers, so it's pretty easy to carry around. It also has the advantage of making enumerations scoped a-la-C++11:
// This doesn't compile, and if it did it wouldn't work anyway
enum colors { salmon, .... };
enum fishes { salmon, .... };
// This, however, works seamlessly.
struct colors_def { enum type { salmon, .... }; };
struct fishes_def { enum type { salmon, .... }; };
typedef typesafe_enum<colors_def> colors;
typedef typesafe_enum<fishes_def> fishes;
The only "hole" that solution provides is that it doesn't address the fact that it doesn't prevent enums of different types (or an enum and an int) from being directly compared, because when you use values directly you force the implicit conversion to int:
if (colors::salmon == fishes::salmon) { .../* Ooops! */... }
But so far I've found such problems can be solved by simply offering a better comparison to the compiler - for example, explicitly providing an operator that compares any two different enum types, then forcing it to fail:
// I'm using backports of C++11 utilities like static_assert and enable_if
template <typename Enum1, typename Enum2>
typename enable_if< (is_enum<Enum1>::value && is_enum<Enum2>::value) && (false == is_same<Enum1,Enum2>::value) , bool >
::type operator== (Enum1, Enum2) {
static_assert (false, "Comparing enumerations of different types!");
}
Though it doesn't seem to break code so far, and it does to explicitly deal with the specific problem without doing something else, I'm not sure it such thing is a thing one "should" do (I suspect it will interfere with enums already taking part in conversion operators declared elsewhere; I'd gladly receive commentary about this).
Combining this with the above typesafe idiom gives something that is relatively close to C++11 enum class in humanibility (readability and maintainability) without having to do anything too obscure. And I have to admit it was fun to do, I had never thought to actually ask the compiler if I was dealing with enums or not...
I think the Java enum would be a good model to follow. Essentially, the Java form would look like this:
public enum Result {
OK("OK"), CANCEL("Cancel");
private final String name;
Result(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
What's interesting about the Java approach is that OK and CANCEL are immutable, singleton instances of Result (with the methods that you see). You cannot create any further instances of Result. Since they're singletons, you can compare by pointer/reference---very handy. :-)
ETA: In Java, instead of doing bitmasks by hand, instead you use an EnumSet to specify a bit set (it implements the Set interface, and works like sets---but implemented using bitmasks). Much more readable than hand-written bitmask manipulation!
I gave an answer to this here, on a different topic. It's a different style of approach which allows most of the same functionality without requiring modification to the original enum definition (and consequently allowing usage in cases where you don't define the enum). It also allows runtime range checking.
The downside of my approach is that it doesn't programmatically enforce the coupling between the enum and the helper class, so they have to be updated in parallel. It works for me, but YMMV.
I am currently writing my own typesafe enum library at https://bitbucket.org/chopsii/typesafe-enums
I am not the most experienced C++ developer ever, but I am writing this due to the shortcomings of the BOOST vault enums.
Feel free to check it out and use them yourself, but they have some (hopefully minor) usability issues, and are probably not at all cross-platform.
Please contribute if you want to. This is my first open source undertaking.
Use boost::variant!
After trying a lot of the above ideas and finding them lacking I hit upon this simple approach:
#include <iostream>
#include <boost/variant.hpp>
struct A_t {};
static const A_t A = A_t();
template <typename T>
bool isA(const T & x) { if(boost::get<A_t>(&x)) return true; return false; }
struct B_t {};
static const B_t B = B_t();
template <typename T>
bool isB(const T & x) { if(boost::get<B_t>(&x)) return true; return false; }
struct C_t {};
static const C_t C = C_t();
template <typename T>
bool isC(const T & x) { if(boost::get<C_t>(&x)) return true; return false; }
typedef boost::variant<A_t, B_t> AB;
typedef boost::variant<B_t, C_t> BC;
void ab(const AB & e)
{
if(isA(e))
std::cerr << "A!" << std::endl;
if(isB(e))
std::cerr << "B!" << std::endl;
// ERROR:
// if(isC(e))
// std::cerr << "C!" << std::endl;
// ERROR:
// if(e == 0)
// std::cerr << "B!" << std::endl;
}
void bc(const BC & e)
{
// ERROR:
// if(isA(e))
// std::cerr << "A!" << std::endl;
if(isB(e))
std::cerr << "B!" << std::endl;
if(isC(e))
std::cerr << "C!" << std::endl;
}
int main() {
AB a;
a = A;
AB b;
b = B;
ab(a);
ab(b);
ab(A);
ab(B);
// ab(C); // ERROR
// bc(A); // ERROR
bc(B);
bc(C);
}
You can probably come up with a macro to generate the boilerplate. (Let me know if you do.)
Unlike other approaches this one is actually type-safe and works with old C++. You can even make cool types like boost::variant<int, A_t, B_t, boost::none>, for example, to represent a value that could be A, B, an integer or nothing which is almost Haskell98 levels of type safety.
Downsides to be aware of:
at-least with old boost -- I'm on a system with boost 1.33 -- you are limited to 20 items in your variant; there is a work-around however
affects compile time
insane error messages -- but that's C++ for you
Update
Here, for your convenience is your typesafe-enum "library". Paste this header:
#ifndef _TYPESAFE_ENUMS_H
#define _TYPESAFE_ENUMS_H
#include <string>
#include <boost/variant.hpp>
#define ITEM(NAME, VAL) \
struct NAME##_t { \
std::string toStr() const { return std::string( #NAME ); } \
int toInt() const { return VAL; } \
}; \
static const NAME##_t NAME = NAME##_t(); \
template <typename T> \
bool is##NAME(const T & x) { if(boost::get<NAME##_t>(&x)) return true; return false; } \
class toStr_visitor: public boost::static_visitor<std::string> {
public:
template<typename T>
std::string operator()(const T & a) const {
return a.toStr();
}
};
template<BOOST_VARIANT_ENUM_PARAMS(typename T)>
inline static
std::string toStr(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & a) {
return boost::apply_visitor(toStr_visitor(), a);
}
class toInt_visitor: public boost::static_visitor<int> {
public:
template<typename T>
int operator()(const T & a) const {
return a.toInt();
}
};
template<BOOST_VARIANT_ENUM_PARAMS(typename T)>
inline static
int toInt(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & a) {
return boost::apply_visitor(toInt_visitor(), a);
}
#define ENUM(...) \
typedef boost::variant<__VA_ARGS__>
#endif
And use it like:
ITEM(A, 0);
ITEM(B, 1);
ITEM(C, 2);
ENUM(A_t, B_t) AB;
ENUM(B_t, C_t) BC;
Notice you have to say A_t instead of A in the ENUM macro which destroys some of the magic. Oh well. Also, notice there's now a toStr function and a toInt function to meet OPs requirement of simple conversion to strings and ints. The requirement I can't figure out is a way to iterate over the items. Let me know if you know how to write such a thing.
Not sure if this post is too late, but there's an article on GameDev.net which satisfies all but the 5th point (ability to iterate over enumerators):
http://www.gamedev.net/reference/snippets/features/cppstringizing/
The method described by the article allows string conversion support for existing enumerations without changing their code. If you only want support for new enumerations though, I'd go with Boost.Enum (mentioned above).
my question is about how to template'ize the name of a class member that should be used.
Maybe a simplified & pseudo example:
/**
Does something with a specified member of every element in a List.
*/
template<membername MEMBER> // <-- How to define such thing?
void doSomething(std::vector<MyClass> all){
for( i=0; i < all.size(); i++)
all[i].MEMBER++; // e.g.; use all[i].MEMBER in same way
}
and
class MyClass{
public:
int aaa, bbb, ccc;
}
and the application:
main(){
vector<MyClass> all = ....
// applicate doSomething() to all aaa's
doSomething<aaa>(all); // or:
doSomething<MyClass::aaa>(all); // or:
doSomething<?????>(all);
}
How should the template definition looks like, that I can switch which member variable (aaa, bbb or ccc) of MyClass is accessed/modified in doSomething(.) ?
In my real world task all MEMBER are of same type, as above.
Thanks,
Tebas
Template parameters are restricted to types, integer constants, pointers/references to functions or objects with external linkage and member pointers -- but no identifiers.
But you could use a member pointer as template parameter:
template<int MyClass::* MemPtr>
void doSomething(std::vector<MyClass> & all) {
for( i=0; i < all.size(); i++)
(all[i].*MemPtr)++;
}
:
doSomething<&MyClass::aaa>(all);
Note that I changed the doSomething function to take a reference instead of accepting the vector by value.
sellibitze's solution is fine (though to be honest not very: see my edit), only it limits you to using only members of type int. A more general solution would be this (although the member is NOT a template parameter here)
#include <vector>
struct MyClass
{
int i;
char c;
};
template <class T>
void DoSomething(std::vector<MyClass>& all, T MyClass::* MemPtr)
{
for(std::vector<MyClass>::size_type i = 0; i < all.size(); ++i)
(all[i].*MemPtr)++;
}
int main()
{
std::vector<MyClass> all;
DoSomething(all, &MyClass::i);
DoSomething(all, &MyClass::c);
}
EDIT:
Also please note that it is not generally a good idea for a pointer to member to be a template parameter inasmuch as only such pointers that are known compile-time can be passed, that is you can't determine the pointer runtime and then pass it as a template param.
I would use lambdas to solve this problem. Something like this:
#include <vector> // vector
#include <algorithm> // for_each
#include <functional> // function
struct MyClass {
void func1() const { std::cout << __FUNCTION__ << std::endl; }
void func2() const { std::cout << __FUNCTION__ << std::endl; }
};
void doSomething(std::vector<MyClass> all, std::function<void (MyClass& m)> f)
{
std::for_each(all.begin(), all.end(), f);
}
int main()
{
std::vector<MyClass> all;
all.push_back(MyClass());
// apply various methods to each MyClass:
doSomething(all, [](MyClass& m) { m.func1(); });
doSomething(all, [](MyClass& m) { m.func2(); });
}
Of course in this case the function doSomething is unnecessary. I could just as simply call for_each directly on all.
I realize this question is a bit old, but none of the answers use the method I have developed, and I would like to share it.
First, in C++ we typically are discouraged from directly accessing member variables and encouraged to provide setters/getters to help enforce hiding of information.
Second, while C++ goes a long way towards eliminating use of macros, they can still accomplish a lot of things that are difficult (or near impossible) with templates and classes.
The following uses a macro to create typed setters & getters for fields in a container member within a class:
//
// Bit(n) -- sets 'n'th bit.
// Bit(0) == 0x1 (b0000001),
// Bit(1) == 0x2 (b0000010),
// Bit(2) == 0x4 (b0000100),
// Bit(3) == 0x8 (b0001000), etc.
//
#define Bit(n) (1 << (n))
//
// BitMask(n) -- creates mask consisting of 'n' bits.
// BitMask(0) == 0x0 (b00000000),
// BitMask(1) == 0x1 (b00000001),
// BitMask(2) == 0x3 (b00000011),
// BitMask(3) == 0x7 (b00000111), etc.
//
#define BitMask(n) (Bit(n) - 1)
//
// BitRange(n, m) -- creates mask consisting of bits between n & m, inclusive.
// BitRange(0, 3) == 0x0f (b00001111),
// BitRange(2, 5) == 0x3c (b00111100),
// BitRange(6, 1) == 0x7e (b01111110), etc.
//
//
#define BitRange(n,m) (BitMask(n) ^ BitMask(m))
#define namedBitField(name, container, start, end, EnumType) \
EnumType name() const \
{return \
(EnumType) \
((container & BitRange(start,end)) \
>> start); \
}; \
void name(EnumType v) {container |= (v << start);}; \
class myTest
{
public:
enum vSet1
{
a = 1,
b = 2,
};
private:
unsigned long holder;
public:
myTest() {};
namedBitField(set1, holder, 0, 3, vSet1);
namedBitField(set2, holder, 4, 5, vSet1);
};
myTest mt;
The namedBitField() macro takes the name for the getter/setter pair, the target container -- holder in this example, the bitfield start/end, and the EnumType that is to be used for values in the bitfield.
If I now use the setter/getter pairs named set1() & set2() in the above example, and attempt to pass POD (plain-old-data) numbers I will get a warning from the compiler.
mt.set1(22); // compiler warns here.
mt.set1();
mt.set2(myTest::vSet1::a); // no warnings.
mt.set2();
No, it is not a "typed bitfield", but it is the next best thing.
No, it is not quite as easy to use as defining bitfields in a struct, but this way you get strong typing via the setters/getters.
Now, you could define the bitfields in structs, make them private, and access them via setters/getters as well, but then the information about where the bits are located is separated from the setters/getters which logically are tied to that information, and as several responders above have pointed out, each C++ compiler can put the bits anywhere they want, so without looking at generated assembler -- or testing on hardware if you are brave -- you cannot be certain things are happening the way you want.
The way the setters/getters created by namedBitField() manipulate the bits in a well-defined order and guarantee bit-order within container, so you can now use the code cross-platform for accessing I/O registers.
Note: in my example I use 'name' as both setter and getter with compiler sorting it out based on use. Some may prefer 'get_name' and 'set_name'. YMMV.
Since the getters/setters are public, and as long as the things you are iterating all derive from the same base class, you can now iterate across the items in a vector -- as above -- and get type-safe getting/setting for the values used in the iteration.