How does multiplication work for C++ enums? - c++

We have a template conversion function intended for use with numeric datatypes. Inside it contains a construct that makes it not compile with types like pointers.
template<class To, class From>
To ConvertTo( From what )
{
assert( 2 * what == what * 2 ); // this will not compile for pointers
//skipped
}
This function compiles and works allright when a enum is passed as the second template parameter:
enum TSomeEnum {
SE_First,
SE_Second
};
TSomeEnum enumValue = SE_First;
int result = ConvertTo<int>( enumValue );
The above code compiles and runs as intended on VC++7.
How does the operation * work for enums? Is it a way to undefined behaviour?

Enums degrade to ints (old C feature) so that why this is working. I don't think it's undefined behaviour although it might be the sort of behaviour you don't want/expect.

Enums are promoted to integers for arithmetic operations.
The values of enums are always numbered up from zero (this is part of the standard), but you can specify whatever values you like. Automatic numbering then procedes incrementally from the last item you explicitly numbered.
The compiler uses the smallest integral type that contains all of the values of an enum to store it.
eg:
enum foo
{
VALUE0, /* = 0 */
VALUE1, /* = 1 */
VALUE3 = 1234,
VALUE4 /* = 1235 */
};

I think peterchen has the ideal answer, but if boost is too much for you, change your current version to:
template<class To, class From>
To ConvertTo( From what, From checkConvertableToInt = 2 )
{
}
C++ doesn't allow implicit conversions from integers to enumerations. Similarly, it's only possible to implicitly convert the null pointer constant (0) to a pointer type.
Some of the other answers refer to an enumeration being implemented as an int or being promoted to an int. This is not true. In C++, an enumeration is defined to have an underlying type that is capable of storing all values in the enumeration. The following enumeration will therefore have an underlying type of 'unsigned int' or a larger signed/unsigned integral type:
enum E {
E0
, E1=MAX_INT+1u
};
The enumeration then follows the rules for its underlying type when you use it in an operation.

Timo described why it works.
For a safer test, you could use boost::TypeTraits

Richard Corden's answer gives a good mechanism to force enums to fail in the assert, however the side effect can cause problems, as you cannot be sure the code inside the assert will always run.
This test should probably by placed in a generic function to avoid the side effects.
template<class To, class From>
To ConvertTo( From what )
{
assert( testIntegralType(what) );
}
template<class T>
void testIntegralType( T val )
{
T v1 = val;
assert( 2*v1 == 2*val );
}

enums are stored as integers, and can even be cast to integers.
The compiler probably stored your above enum as
enum TSomeEnum {
SE_First = 0,
SE_SEcond = 1
};
I'm not sure if this numbering system is part of the C/C++ standard or just how compilers do it, but I've always seen them in order.
Anyway, to answer your question, since they're stored as ints underneath, it should be able to be multiplied. Some compilers may give you a warning about type conversion though.

Related

Templated function can't convert 'int' to nullptr_t

TL;DR:
Why can't templated functions access the same conversions that non-templated functions can?
struct A {
A(std::nullptr_t) {}
};
template <typename T>
A makeA(T&& arg) {
return A(std::forward<T>(arg));
}
void foo() {
A a1(nullptr); //This works, of course
A a2(0); //This works
A a3 = makeA(0); //This does not
}
Background
I'm trying to write some templated wrapper classes to use around existing types, with the goal of being drop-in replacements with minimal need to rewrite existing code that uses the now-wrapped values.
One particular case I can't get my head around is as follows: we have a class which can be constructed from std::nullptr_t (here called A), and as such, there's plenty of places in the code base where someone has assigned zero to an instance.
However, the wrapper cannot be assigned a zero, despite forwarding the constructors. I have made a very similar example that reproduces the issue without using an actual wrapper class - a simple templated function is sufficient to show the issue.
I would like to allow that syntax of being able to assign zero to continue to be allowed - it isn't my favourite, but minimising friction to moving to newer code is often a necessity just to get people on board with using them.
I also don't want to add a constructor that takes any int other than zero because that's very much absurd, was never allowed before, and it should continue to be caught at compile time.
If such a thing is not possible, it would satisfy me to find an explanation, because with as much as I know so far, it makes no sense to me.
This example has the same behaviour in VC++ (Intellisense seems to be OK with it though...), Clang, and GCC. Ideally a solution will also work in all 3 (4 with intellisense) compilers.
A more directly applicable example is follows:
struct A {
A(){}
A(std::nullptr_t) {}
};
template <typename T>
struct Wrapper {
A a;
Wrapper(const A& a):a (a) {}
template <typename T>
Wrapper(T&& t): a(std::forward<T>(t)){}
Wrapper(){}
};
void foo2() {
A a1;
a1 = 0; // This works
Wrapper<A> a2;
a2 = 0; //This does not
}
Why has the compiler decided to treat the zero as an int?
Because it is an integer.
The literal 0 is a literal. Literals get to do funny things. String literals can be converted into const char* or const char[N], where N is the length of the string + NUL terminator. The literal 0 gets to do funny things too; it can be used to initialize a pointer with a NULL pointer constant. And it can be used to initialize an object of type nullptr_t. And of course, it can be used to create an integer.
But once it gets passed as a parameter, it can't be a magical compiler construct anymore. It becomes an actual C++ object with a concrete type. And when it comes to template argument deduction, it gets the most obvious type: int.
Once it becomes an int, it stops being a literal 0 and behaves exactly like any other int. Not unless it is used in a constexpr context (like your int(0)), where the compiler can figure out that it is indeed a literal 0 and therefore can take on its magical properties. Function parameters are never constexpr, and thus they cannot partake in this.
See [conv.ptr]/1:
A null pointer constant is an integer literal with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type [...]
So the integer literal 0 can be converted to a null pointer. But if you attempt to convert some other integer value, that is not a literal, to a pointer type then the above quote does not apply. In fact there is no other implicit conversion from integer to pointer (since none such is listed in [conv.ptr]), so your code fails.
Note: Explicit conversion is covered by [expr.reinterpret.cast]/5.

Detecting the types of individual enumeration constants

The code below prints unsigned int as the underlying type of all the constants inside the enum Test
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
struct Test
{
enum { a = true, b = 1 };
};
static_assert(std::is_same<
std::underlying_type_t<decltype(Test::a)>,
std::underlying_type_t<decltype(Test::b)>>::value, ""
);
int main()
{
int status;
auto const& bi = typeid(std::underlying_type_t<decltype(Test::a)>);
std::cout << abi::__cxa_demangle(bi.name(), 0, 0, &status); // unsigned int
}
Live Example. This also happens if Test contains two separate enums with a and b as before.
Question: is it possible to detect that Test::a is initialized with bool and Test::b with int? Is there any experimental code for this in any of the Reflection Study Group proposals for C++17?
NOTE: I know I can work around it by replacing Test with
struct Test
{
static constexpr auto a = true;
static constexpr auto b = 1;
};
but I find the enum version slightly less verbose in its usage.
It is not possible and I consider it very unlikely that it will ever be possible.
The reason is that a and b are values of the (in your case unnnamed) enum. Thus they are, by definition, of the type of the enum, meaning: Of the same type. The expressions used to initialize them and their respective types are only used to "calculate" the underlying type of the enum, not of any individual values.
Considering this fact, I think that even reflection will not help to recover the information as the type of the initializing expression is abstracted away when you look at an enum's value.
What you'd need is an even deeper level of inspection where you'd need to access the expression used to initialize the values. That would mean that compilers will have to store a lot of additional information for every variable, values, etc. (since this would be a general thing not just for enums).
Consider what that means:
Increased compile times
Increased memory usage when compiling
Every value would effectively now have two types, the type it is declared as and the type of the expression it was initialized from
The last point is what I would consider the real catastrophe for the language. A value should have a single type, the expression used to initialized the value should not be accessible in any way. This is what abstraction is about, breaking it could lead to all kinds of subtle dependencies and a lot of complexity.
Disclaimer: This is just my personal opinion, I can't speak for anyone on the committee or in the working groups.
You could differentiate int enum values from non-ints as following:
struct Test
{
enum : short { a = true };
enum : int { b = 1 };
// enum : bool { c = false };
};
Unfortunately, VC2010 fails to compile a bool as underlying type, which is probably not considered as an integral type. This might not be an issue if your use case only requires separating ints from non-ints.

Let the compiler make the final choice which type to use

This question requires knowledge of C++ template meta-programming as (indirectly) expression templates are involved. I say indirectly because its not directly a question on expression templates, but involves C++ type computations. If you don't know what that is please don't answer this question.
To avoid putting out a question without enough background information let me elaborate a bit on the general problem I am trying to solve and then go to the more specific parts.
Suppose you have a library that provides Integers that the user can do calculations with just like with ints.
Furthermore it is possible to construct a Integer from an int. Just like:
Integer<int> i(2);
Internally my Integer class is a class template:
template<class T>
class Integer {
// cut out
};
So I can define it on whatever integer type I like.
Now without changing the API, I would like to change the library in a way that if Integer was constructed from an int it should be represented internally by a different type, say IntegerLit. The reason for this is that I can speed up some calculation knowing that an instance of Integer was created from an int (can pass it as a int argument to a function instead of as a general object described by a base pointer + separate data. This just as a comment.)
It is essential that the type is different when constructing from an int because I need the compiler to take up different code paths depending on whether constructed from an int or not. I cannot do this with a runtime data flag. (The reason in short: The compiler generates a function that takes either an int or the above mentioned more general type of object depending on the type.)
Having this said I run into a problem: When the uses does something like this:
Integer<int> a,b(2);
a = b + b;
Here a should be the general Integer and b the specialized IntegerLit. However, my problem is how to express this in C++ as the user is free to use the very same type Integer to define her variables.
Making the types polymorphic, i.e. deriving IntegerLit from Integer won't work. It looks fine for a moment. However since the user creates instances of Integer (the base class) that won't work because it is the base class the compiler sticks into the expression tree (this is why expression templates are involved in the question). So again no distinction is possible between the two cases. Doing a RTTI check a la dynamic cast is really not what I want on that point.
More promising seems to be adding a literal template parameter bool lit to the type saying if it was constructed from an int or not. The point is to not specify the conversion rule for one not literal one but do specify it for the other case.
However, I can't get that to work. The following code only compiles (GCC 4.7 C++11) if not constructing from an int. Otherwise it fails because the Integer is not specified with true as the value for lit. So the compiler searches the default implementation which doesn't have the conversion rule. It is not an option changing the API and requiring to write Integer<int,true> when constructing from an int.
template<class T,bool lit=false>
class Integer
{
public:
Integer() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
T F;
};
template<>
template<class T>
class Integer<T,true>
{
public:
Integer(int i) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
T F;
};
I am starting wondering if something like this is possible with C++.
Is there maybe a new feature of C++11 that can help here?
No, this isn't how C++ works. If you define b as Integer b, then it's an Integer. THis applies regardless of the expression which is subsequently used to initialize b.
Also, consider the following: extern Integer b;. There's an expression somewhere else that initializes b, yet the compiler still has to figure out here what type b has. (Not "will have", but "has").
You can't do that, exactly anyways.
But using "auto" you can come close.
// The default case
Integer<int> MakeInt()
{
return Integer<int>();
}
// The generic case
template <class T>
Integer<T> MakeInt(T n)
{
return Integer<T>(n);
}
// And specific to "int"
Integer<IntegerLit> MakeInt(int n)
{
return Integer<IntegerLit>(n);
}
auto a = MakeInt();
auto b = MakeInt(2);
auto c = MakeInt('c');
auto d = MakeInt(2.5);
You can't do that. Once you've said a variable is Integer<int> that is the variable's type. What you can do is make the underlying rep of the Integer vary depending on which constructor is used, something like this:
template<class T>
class Integer {
// cut out
Integer() : rep_(IntRep()) {}
explicit Integer(int val) : rep_(IntLitRep(val)) {}
private:
boost::variant<IntRep, IntLitRep> rep_;
};
Then you can easily determine which variant version is active and utilize different code paths when needed.
EDIT: In this case even though the type of the Integer is the same, you can easily use template functions to make it appear that it's behaving as two separate types (since the rep changes effective type).

Is passing an enum value to an int parameter non standard?

Example:
enum SomeEnum
{
DD,
PP,
NN
};
void someFunc(int a)
{
}
int main()
{
SomeEnum e = DD;
someFunc(a) // calls someFunc with value 0
return 0;
}
This works in MSVC but is it non standard?
Thanks
An enum has an underlying integer type (the type used to store the value of the enum), and the enum value can be implicitly converted to that integer type's value.
In your case the underlying type is int, and the value is 0. Everything is okay.
The identiļ¬ers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.
6.7.2.2 here http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
It's absolutely valid because, as GManNickG and tomato said, all enums are of type int (in fact, in C, enums ARE ints and you can assign them values outside the scope of the enum.
typedef enum _foo
{
val1 = 57
} foo;
...
foo f = 99; // compiles in C but not C++
In fact, most compilers won't complain if the function argument type was bool or float or some other primitive number type because enums act as constant integer values like 0, -1, 200, etc...
What I'd say though, is that, if you have control over someFunc's signature and you want to ensure in C++ that no invalid values are passed in, change it to be
void someFunc(SomeEnum a);
for more typesafety
Also, always initialize your first enum value at least. I may be wrong on this but, back in the day, the compiler was allowed to pick an arbitrary starting value for your enum. Most of the time it picked 0 but not always. Even if that's not the case, it makes the code a little more self documenting and obvious.

Using elements of a constant array as cases in a switch statement

I'm attempting to map a set of key presses to a set of commands. Because I process the commands from several places, I'd like to set up a layer of abstraction between the keys and the commands so that if I change the underlying key mappings, I don't have to change very much code. My current attempt looks like this:
// input.h
enum LOGICAL_KEYS {
DO_SOMETHING_KEY,
DO_SOMETHING_ELSE_KEY,
...
countof_LOGICAL_KEYS
};
static const SDLKey LogicalMappings[countof_LOGICAL_KEYS] = {
SDLK_RETURN, // Do Something
SDLK_ESCAPE, // Do Something Else
...
};
// some_other_file.cpp
...
switch( event.key.keysym.key ) {
case LogicalMappings[ DO_SOMETHING_KEY ]:
doSomething();
break;
case LogicalMappings[ DO_SOMETHING_ELSE_KEY ]:
doSomethingElse();
break;
...
}
When I try to compile this (gcc 4.3.2) I get the error message:
error: 'LogicalMappings' cannot appear in a constant-expression
I don't see why the compiler has a problem with this. I understand why you're not allowed to have variables in a case statement, but I was under the impression that you could use constants, as they could be evaluated at compile-time. Do constant arrays not work with switch statements? If so, I suppose I could just replace the array with something like:
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN;
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE;
...
But that seems much less elegant. Does anybody know why you can't use a constant array here?
EDIT: I've seen the bit of the C++ standard that claims that, "An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5)...". I still don't see why a constant array doesn't count as an "enumeration type initialized with a constant expression." It could just be that the answer to my question is "because that's the way that it is," and I'll have to work around it. But if that's the case, it's sort of disappointing, because the compiler really could determine those values at compile-time.
Referring to sections of the C++ standard: 6.4.2 requires that case expressions evaluate to an integral or enumeration constant. 5.19 defines what that is:
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
So if your question was "why does the compiler reject this", one answer is "because the standard says so".
Array references aren't "constant enough", regardless.
You just need to do the mapping slightly differently. You want the same action to occur when the logical key is pressed, so use the logical key codes in the case clauses of the switch statement. Then map the actual key code to the logical code, possibly in the switch itself, or possibly before-hand. You can still use the LogicalMappings array, or a similar construct. And, as an aid to G11N (globalization), you can even make the mapping array non-constant so that different people can remap the keys to suit their needs.
I'll go on a limb here since nobody else replied to this and I've been mostly doing Java recently, not C++, but as far as I seem to recall an array lookup is not considered a constant integer even if the result of the lookup can be determined at compile time. This may even be an issue in the syntax.
Is there a comparison operator defined for the "LogicalMappings"? If not then that is the error.
There is a library called signal in boost that will help you create a event mapping abstraction.If you have time this should be better approach
you could also use an array of function pointers or functors (I suppose functor addresses), to avoid the switch statement altogether & just go from array index -> function pointer / functors directly.
for example (warning, untested code follows)
class Event // you probably have this defined already
{
}
class EventHandler // abstract base class
{
public:
virtual void operator()(Event& e) = 0;
};
class EventHandler1
{
virtual void operator()(Event& e){
// do something here
}
};
class EventHandler2
{
virtual void operator()(Event& e){
// do something here
}
};
EventHandler1 ev1;
EventHandler2 ev2;
EventHandler *LogicalMappings[countof_LOGICAL_KEYS] = {
&ev1,
&ev2,
// more here...
};
// time to use code:
Event event;
if (event.key.keysym.key < countof_LOGICAL_KEYS)
{
EventHandler *p = LogicalMappings[event.key.keysym.key];
if (p != NULL)
(*p)(event);
}
A compiler guru at work explained this to me. The problem is that the array itself is constant, but indices to it aren't necessarily const. Thus, the expression LogicalMappings[some_variable] couldn't be evaluated at compile-time, so the array winds up being stored in memory anyway rather than getting compiled out. There's still no reason why the compiler couldn't statically evaluate array references with a const or literal index, so what I want to do should theoretically be possible, but it's a bit trickier than I'd thought, so I can understand why gcc doesn't do it.