I'm a big fan of C++'s strong-typing features and what I like the most is to use enumerations while dealing with limited sets of data.
But enumerations lack some useful features, for example operators:
enum class Hex : int
{
n00, n01, n02, n03,
n04, n05, n06, n07,
n08, n09, n10, n11,
n12, n13, n14, n15
};
for (Hex h = Hex::n0; h <= Hex::n15; ++h) // Oops! no 'operator ++'
{ /* ... */ }
Is easy to get rid of the lack of operators creating a free operator on the same scope:
Hex &operator ++(Hex &h)
{
int r = static_cast<int>(Hex);
h = static_cast<Hex>(r + 1);
return h;
}
for (Hex h = Hex::n0; h <= Hex::n15; ++h) // Now the '++h' works!
{
std::cout << std::dec << int(h) << ": "
<< std::hex << int(h) << '\n';
}
But this approach is more a nuisance than a solution, because it can break the value limitation of the enumeration: applying ++h while h equals to Hex::n15 will set h to he value 16, wich is out of the Hex scope of values while h is still of the type Hex!, This problem is more evident in other enumerations:
enum class Prime : int
{
n00 = 2, n01 = 3, n02 = 5, n03 = 7,
n04 = 11, n05 = 13, n06 = 17, n07 = 19,
n08 = 23, n09 = 29, n10 = 31, n11 = 37,
n12 = 41, n13 = 43, n14 = 47, n15 = 53
};
Prime &operator ++(Prime &p)
{
// How to implement this?! will I need a lookup table?
return p;
}
This problem was a surprise for me; I was betting that storing an incorrect value into an enumeration value will throw an exception. So, for now I was wondering if there's an elegant way to deal with this enumeration's weaknesses, the goals I want to achieve are:
Find a comfortable way to use enumeration values in loops.
Ensuring enumation data consistency between operations.
Additional questions:
Is there a reason for not throwing an exception when an enumeration data gets a value that is out of its possible values?
There is a way to deduce the type associated with an enumeration class?, the int type in the enumerations Hex and Prime.
As you've noticed, enum in C++ is not an enumerated type,
but something more complex (or more mixed). When you define an
enum, you define in fact two things:
An integral type with a legal range sufficient to contain an
or of all of the enumerated values. (Technically: the range
is 2^n - 1, where n is the number of bits necessary to
hold the largest value.)
A series of named constants having the newly defined type.
(I'm not sure what happens with regards to the range if you
explicitly specify an underlying type.)
Given your enum Prime, for example, the legal values would be
all integers in the range [0...64), even if all of these
values don't have a name. (At least if you didn't specifically
say that it should be an int.)
It's possible to implement an iterator for enums without
initializers; I have a program which generates the necessary
code. But it works by maintaining the value in an integral type
which is large enough to contain the maximum value plus one. My
machine generated implementations of ++ on such an enum will
assert if you try to increment beyond the end. (Note that
your first example would require iterating h one beyond the
last value: my implementation of the various operators does not
allow this, which is why I use an iterator.)
As to why C++ supports the extended range: enum are often used
to define bit masks:
enum X
{
a = 0x01,
b = 0x02,
c = 0x04,
all = a | b | c,
none = 0
};
X operator|( X lhs, X rhs )
{
return X((int)lhs | (int)rhs);
}
// similarly, &, |= and &=, and maybe ~
One could argue that this use would be better handled by
a class, but the use of enum for it is ubiquitous.
(FWIW: my code generator will not generate the ++, -- and
the iterators if any of the enum values has an explicitly
defined value, and will not generate |, & etc. unless all of
the values have explicitly defined values.)
As to why there is no error when you convert some value outside
the legal range (e.g. 100, for X, above) is simply in keeping
with the general philosophy inherited from C: it's better to be
fast than to be correct. Doing extra range checking would
entail additional runtime cost.
Finally with regards to your last example: I don't see this as
a realistic use of enum. The correct solution here is an
int[]. While the C++ enum is rather a mixed breed, I would
only use it as a real enumerated type, or for bit masks (and
only for bit masks because it is such a widely established
idiom).
You can use a switch:
class Invalid {};
Prime& operator ++(Prime& p)
{
switch(p)
{
case n00: return n01;
case n01: return n02;
case n02: return n03;
case n03: return n04;
case n04: return n05;
case n05: return n06;
case n06: return n07;
case n07: return n08;
case n08: return n09;
case n09: return n10;
case n10: return n11;
case n11: return n12;
case n12: return n13;
case n13: return n14;
case n14: return n15;
// Here: 2 choices: loop or throw (which is the only way to signal an error here)
case n15: default: throw Invalid();
}
}
But note that this is not the right use of enums. I personally find this error-prone. If you want to enumerate integers, you can use an array of ints to do this, or for the case of prime numbers, a function (in mathematical sense: int nextPrime(int)).
Related
Let's say I have a strongly typed enum type like this:
enum class message : int {
JOIN = 0,
LEAVE = 4,
SPAWN = 1,
}
And I need to safely (safely in this case means discarding invalid variants) convert it from it's underlying type (int).
For this purpose, I have a function to convert it for me:
std::optional<message> get_message(int num) {
return num == (int)message::JOIN || num == (int)message::LEAVE || num == (int)message::SPAWN ? (message)num : {};
}
This works, but is long to write and prone to mistakes, especially for enums with a larger number of variants.
Is there a way to automate this process in C++17?
Talking about underlying type, we notice that this class merely obtains a type using another type as model, but it does not transform values or objects between those types.
As an option to simplify the function you could work by iterating in the enum,or as others said before with some type of container, by iterating the same enum as an example here: How can I iterate over an enum?
and more information about enum just in case: https://learn.microsoft.com/en-us/cpp/cpp/enumerations-cpp?view=vs-2019
What is the best way to have three value Boolean variable in c++?
I would like to have fields set to true, false or not set at all in my array.
If I declare them this way:
t[0] = true;
t[1] = false;
t[2] = NULL;
When I test the condition I get:
t[2] is false
You might want to look at boost.tribool: http://www.boost.org/doc/libs/1_60_0/doc/html/tribool.html
This should work:
t[0] = true;
t[1] = false;
t[2] = -1;
Or if you only need 3 states but perhaps would like more at some point, an enum is great:
enum STATES
{
NULL_STATE = -1, // you can manually specify -1 to give it a special case value
FALSE, // will be equal to 0
TRUE // will be equal to 1
};
No matter what though, 0/false is the only thing that returns false in an if() statement. -1 and true both return true.
You may want to use a switch like this to deal with 3+ states:
switch (var) // may need to cast: (int)var
{
case 1:
case 0:
case -1:
};
Alternatively if you want to stick to an if statement block, you could do something like this:
if (var == -1) // or (var == NULL_STATE)
{}
else if (var) // true condition
{}
else // false
{}
Consider using std::experimental::optional<bool> (if your C++ standard library has it), or boost::optional<bool> (www.boost.org).
I believe std::optional is a candidate for C++17 so if you adopt one of the above then your refactoring effort to C++17 ought to be minimal.
If you don't like using things that are not (yet?) in the "proper" C++ standard library, then consider
Something based around std::unique_ptr<bool>
A std::pair<bool, bool>
A good old-fashioned enum with 3 values.
You could use boost::optional
http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/index.html
boost::optional<bool> myBooleanVariable;
I agree that tribool can be better if you don't need the uninitialised values to be NULL. Where comparing optional and tribool, the documentation says:
First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized optional. It should be carefully considered if an optional instead of a tribool is really needed.
Source: http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/boost_optional/a_note_about_optional_bool_.html
What is the best way to have three value Boolean variable in c++?
Boolean values by definition only have 2 possible states - True or False.
If you want to have another state for 'invalid' or 'not set' then you need to encapsulate the bool variable in some other data-types.
The right solution depends on what you want to do with that variable.
For simple comparisons (if-else and switch) scoped enums (c++11) should be preferred.
enum class tristate{true,false,undefined=0};
They are simple, easy to use and understand and offer type safety over plane old enums. As they are type-safe you can not accidentally compare it with different types of enums or numeral types, But it also means you can not use bitfiddling and integer-tricks either.
Unless a different type is specified an enum class is a numerical type which gets initialized to '0'. that means by assigning the value '0' to one of the enum-values you can make that the default state.
tristatet[7];
t[1] = tristate::true;
t[2] = tristate::false;
t[3] = tristate::undefined;
t[4] = false; //error
t[5] = 0; //error
t[6] = null; //error
t[0] == true; //error
t[0] == tristate::true; // false
t[0] == tristate::undefined; // true
Of course you can use that in a switch-statement:
switch(t[2]) {
case tristate::true:
foo(); break;
case tristate::false:
bar(); break; //t[2] was set to tristate::false
case tristate::undefined :
doNothing(); break;
}
You can use std::optional for this:
std::optional<bool> t[3];
t[0] = true;
t[1] = false;
t[2] = std::nullopt;
for (auto const& i : t)
if (i.has_value()) std::cout << i.value() << '\n';
output:
1
0
I also believe an enum declaration is the cleaner and simplest solution.
A small note on the size of the new type: enums are usually (depending of course on the compiler) backed by integers, so you are allocating something like 32 or 64 bits to actually use 2 bits.
In newer C++ (C++11), you can specify the underlying type of the enum (to an existing integral type). For example:
enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
...
enum tribool f = tribool::False;
I need a bitset with a slightly diffrent behavior when asigning variables with integer type to a specific bit. The bit should be set to zero if the assigned integer is smaller then one, and to one elsewise.
As a simple solution I copied the STL bitset, replaced the classname with altbitset, adjusted namespaces and include guard and added following function under reference& operator=(bool __x) in the nested reference class:
template <typename T>
reference& operator=(T i) {
if (i<1) return operator=(false);
return operator=(true);
}
It works as expected.
Question is if there is a better way doing this.
You shouldn't copy a library just to add a new function. Not only that, the new function is wildly unintuitive and could possibly be the source of errors for even just reading the code, let alone writing it.
Before:
bv[n] = -1; // I know a Boolean conversion on -1 will take place
assert(bv[n]); // of course, since -1 as a Boolean is true
After:
bv[n] = -1; // I guess an integer < 1 means false?
assert(bv[n]); // Who changed my bitvector semantics?!
Just write it out so it makes sense in your domain:
bv[n] = (i < 1);
Remember: simplest doesn't always mean fewest characters, it means clearest to read.
If you do want to extend the functionality of existing types, you should do so with free functions:
template <typename BitSet, typename Integer>
auto assign_bit_integer(BitSet& bits, const std::size_t bit, const Integer integer) ->
typename std::enable_if<std::is_integral<Integer>::value,
typename BitSet::reference>::type
{
return bits[bit] = (integer < 1);
}
Giving:
std::bitset<8> bits;
assign_bit_integer(bits, 0, 5);
// ERROR: assign_bit_integer(bits, 0, 5.5);
But for such a small function with no clear "obvious" name that describes what it does concisely(assign_bit_true_if_less_than_one_otherwise_false is verbose, to say the least), just write out the code; it says the same thing anyway.
I copy and pasted some code that increments an enum:
myenum++;
This code worked fine as it was compiled in VS.NET C++ 2003
I am now developing in VS 6.0 and get the error:
error C2676: binary '++' : 'enum
ID' does not define this
operator or a conversion to a type
acceptable to the predefined operator
How can I get this to behave the same in 6.0?
I see nothing wrong with defining operator++ on a well understood enum. Isn't that the purpose of operator overloading? If the context made no sense (e.g. an enum with holes in it), then of course it doesn't make sense. Defining operator* for a class called Complex that implement complex numbers is not just valid but a great application of mathematical operator overloading in C++!
If the developer defines an enum where operator++ makes obvious and intuitive sense to the clients of that enum, then that's a good application of that operator overload.
enum DayOfWeek {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
inline DayOfWeek operator++(DayOfWeek &eDOW, int)
{
const DayOfWeek ePrev = eDOW;
const int i = static_cast<int>(eDOW);
eDOW = static_cast<DayOfWeek>((i + 1) % 7);
return ePrev;
}
an enum may be intergral but it doesn't mean it covers a continuous range.
This
enum {
A,
B,
C,
}
May Will default to
enum {
A = 0,
B = A + 1,
C = B + 1,
}
and so you could get away with
int a = A;
a++;
However if you have
enum {
A = 2,
B = 4,
C = 8,
}
now +1 ain't gonna work.
Now, if you also had things like
enum {
FIRST,
A = FIRST,
B,
C,
LAST = C
}
then when iterating the enum would you do A and C twice?
What is the purpose of iterating the enum? do you wish to do 'for all' or for some subset, is there actually an order to the enum?
I'd throw them all in a container and iterate that instead
unordered - use a set
ordered - a vector or list
Please try to convert to int, add one (+1) and convert back to the enum.
myenum=(myenum_type)((int)myenum+1);
It's ugly but it works.
Could one write a function that returns the number of elements in an enum? For example, say I have defined:
enum E {x, y, z};
Then f(E) would return 3.
Nope.
If there were, you wouldn't see so much code like this:
enum E {
VALUE_BLAH,
VALUE_OTHERBLAH,
...
VALUE_FINALBLAH,
VALUE_COUNT
}
Note that this code is also a hint for a (nasty) solution -- if you add a final "guard" element, and don't explicitly state the values of the enum fields, then the last "COUNT" element will have the value you're looking for -- this happens because enum count is zero-based:
enum B {
ONE, // has value = 0
TWO, // has value = 1
THREE, // has value = 2
COUNT // has value = 3 - cardinality of enum without COUNT
}
There are ways, but you have to work... a bit :)
Basically you can get it with a macro.
DEFINE_NEW_ENUM(MyEnum, (Val1)(Val2)(Val3 = 6));
size_t s = count(MyEnum());
How does it work ?
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#define DEFINE_NEW_ENUM(Type_, Values_)\
typedef enum { BOOST_PP_SEQ_ENUM(Values_) } Type_;\
size_t count(Type_) { return BOOST_PP_SEQ_SIZE(Values_); }
Note that length could also be a template specialization or anything. I dont know about you but I really like the expressiveness of a "Sequence" in BOOST_PP ;)
No, this is a VFAQ and the answer is NO!!
Not without kludging anyway.
Even that trick about with a final entry only works if none of the values are non-default. E.g.,
enum B {
ONE, // has value = 0
TWO, // has value = 1
THREE=8, // because I don't like threes
COUNT // has value = 9
}
No. For one thing, you can't take types as parameters (just instances of types)