What are the allowed enumerator initializer types in C++11 scoped enums? - c++11

The following code compiles cleanly with GCC 5.2.1
enum class some_enum
{
first = static_cast<some_enum>(1),
};
but fails in clang 3.6.2:
$ clang++ -std=c++11 enum.cpp -c
enum.cpp:15:13: error: value of type 'some_enum' is not implicitly convertible to 'int'
first = static_cast<some_enum>(1),
^~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
According to my reading of the standard (§7.2, paragraph 5), the enumerator initializer expression must have the same type as the underlying type of the enumeration in this case. Which happens to be int, not some_enum.
So I think clang is correct to reject this, and that this is a bug in GCC. Can anyone with a better understanding of the standard confirm, before I report this as a bug to GCC?
Edit: to explain my reasoning regarding the standard
Here is my understanding of 7.2 paragraph 5:
Each enumeration defines a type that is different from all other
types. Each enumeration also has an underlying type. The underlying
type can be explicitly specified using enum-base; if not explicitly
specified, the underlying type of a scoped enumeration type is int. In
these cases, the underlying type is said to be fixed.
So, since this a scoped enumeration with no explicit enum-base, its underlying type is fixed as int.
Following the closing brace of an enum-specifier, each enumerator
has the type of its enumeration.
In other words, outside the enum body, an individual enumerator (i.e., named entry within the enum) is has the same type as the entire enum.
If the underlying type is fixed, the type of each enumerator prior to
the closing brace is the underlying type...
Since we're dealing with a scoped enum which always has fixed underlying type, the type of each enum entry within the enum body has the same type as the enumeration's underlying type. In this case, within the body, the enumerators have type int.
...and the constant-expression in the enumerator-definition shall
be a converted constant expression of the underlying type (5.19);
if the initializing value of an enumerator cannot be represented
by the underlying type, the program is ill-formed.
In the example case, the initializer has type some_enum, which as a C++11 scoped enum cannot be converted to a constant expression of the underlying type without an explicit conversion. So the program is ill-formed.

Related

Why can you assign a slice to an empty interface but not cast it to the same empty interface

Why does golang not support casting a slice to an empty interface? You can however work around it, by declaring a variable with an empty interface as type and assinging the slice to that variable. Why are those not the same thing?
Example: https://play.golang.com/p/r4LXmR4JhF0
First, Go doesn't support casting at all.
There simply is no type casting in Go*.
What you're attempting to do is a type assertion.
There are two reasons your attempt fails. Both are explained by the compiler:
invalid type assertion: slice.(<inter>) (non-interface type []interface {} on left)
You cannot type-assert any non-interface type to an interface.
non-name *castedSlice on left side of :=
*castedSlice is invalid in this context.
Assignment is the correct approach if you want to store a slice in a variable of type interface{}. You can do this a few ways:
As you have discovered, this works:
var result interface{}
result = slice
You can combine those two lines:
var result interface{} = slice
You can also do a short variable declaration:
result := interface{}{slice}
*lest anyone nitpick the statement: It is technically possible to accomplish the same as type casting in Go, with use of the unsafe package, but as this is outside of the language spec, and is, by definition, unsafe, I think it's still a reasonable statement that Go does not support type casting.

memcpy from one type to another type. How do we access the destination afterwards?

uint32_t u32 = 0;
uint16_t u16[2];
static_assert(sizeof(u32) == sizeof(u16), "");
memcpy(u16, &u32, sizeof(u32)); // defined?
// if defined, how to we access the data from here on?
Is this defined behaviour? And, if so, what type of pointer may we use to access the target data after the memcpy?
Must we use uint16_t*, because that suitable for the declared type of u16?
Or must we use uint32_t*, because the type of the source data (the source data copied from by memcpy) is uint_32?
(Personally interested in C++11/C++14. But a discussion of related languages like C would be interesting also.)
Is this defined behavio[u]r?
Yes. memcpying into a pod is well-defined and you ensured that the sizing is the correct.
Must we use uint16_t*, because that suitable for the declared type of u16?
Yes, of course. u16 is an array of two uint16_ts so it must be accessed as such. Accessing it via a uint32_t* would be undefined behavior by the strict-aliasing rule.
It doesn't matter what the source type was. What matters is that you have an object of type uint16_t[2].
On the other hand, this:
uint32_t p;
new (&p) uint16_t(42);
std::cout << p;
is undefined behavior, because now there is an object of a different type whose lifetime has begin at &p and we're accessing it through the wrong type.
The C++ standard delegates to C standard:
The contents and meaning of the header <cstring> are the same as the C standard library header <string.h>.
The C standard specifies:
7.24.1/3 For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).
So, to answer your question: Yes, the behaviour is defined.
Yes, uint16_t* is appropriate because uint16_t is the type of the object.
No, the type of the source doesn't matter.
C++ standard doesn't specify such thing as object without declared type or how it would behave. I interpret that to mean that the effective type is implementation defined for objects with no declared type.
Even in C, the source doesn't matter in this case. A more complete version of quote from C standard (draft, N1570) that you are concerned about, emphasis mine:
6.5/6 [...] If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. [...]
This rule doesn't apply, because objects in u16 do have a declared type

Why literal value has no type?

Type Inference is a powerful attribute of Swift. It means the compiler can infer the literal's type from its value provided by the programmer, the explicit type specification is not needed.
For example var IntNum = 3; the compiler can infer that the variable IntNum is of type Int. In Xcode, If user hits the key and clicks on the variable name, here IntNum, then Xcode tells you what the type it is.
However, if I did that on the literal value 3, Xcode provides nothing. I guess, the literal value I put on the screen simply has no type at all, only the object variable and constant has the type property.
I just guess so, can someone explain that to me?
Cheers
SL
That's right.
From the documentation
Type Safety and Type Inference
Type inference is particularly useful when you declare a constant or
variable with an initial value. This is often done by assigning a
literal value (or literal) to the constant or variable at the point
that you declare it. (A literal value is a value that appears directly
in your source code)
...
If you combine integer and floating-point literals in an expression, a
type of Double will be inferred from the context:
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
The literal value of 3 has no explicit type in and of itself, and so
an appropriate output type of Double is inferred from the presence of
a floating-point literal as part of the addition.

Can I use const & as parameter of a constexpr function?

I'm writing a constrexpr function taking either a CArray T(&)(N), either a std::array.
I think I have to write 2 functions (if you know better I would be happy to know),
But I'm concerned about what I wrote with the std::array
constexpr float LinInterp01(const std::array<float, N>& inArray, float inX);
Is it correct when writing a constrexpr function to pass by const & or not?
I think it should be because at compile time the compiler would instanciate a copy and there is no notion of L Value, at compile time.
Could someone explain me this?
C++ standard section § 7.1.5 [dcl.constexpr]
The definition of a constexpr function shall satisfy the following constraints:
— it shall not be virtual (10.3);
— its return type shall be a literal type;
— each of its parameter types shall be a literal type;
And section § 3.9 [basic.types]
A type is a literal type if it is:
— void; or
— a scalar type; or
— a reference type; or
— an array of literal type; or
— a class type (Clause 9) that has all of the following properties:
— it has a trivial destructor,
— it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template
that is not a copy or move constructor, and
— all of its non-static data members and base classes are of non-volatile literal types.
So yes, you can pass parameters by reference to constexpr functions.
Now whether or not your function calls will actually be evaluated at compile time depends on the body and calls of LinInterp01.

Does the actual value of a enum class enumeration remain constant/invariant?

Given code for an incomplete server like:
enum class Command : uint32_t {
LOGIN,
MESSAGE,
JOIN_CHANNEL,
PART_CHANNEL,
INVALID
};
Can I expect that converting Command::LOGIN to an integer will always give the same value?
Across compilers?
Across compiler versions?
If I add another enumeration?
If I remove an enumeration?
Converting Command::LOGIN would look something like this:
uint32_t number = static_cast<uint32_t>(Command::LOGIN);
Some extra information on what I am doing here. This enumeration is fed onto the wire by converting it to an integer sending it along to the server/client. I do not really particularly care what the number is, as long as it will always stay the same. If it will not stay the same, then obviously I will have to provide my own numbers through the usual way.
Now my sneaking suspicion is that it will change depending on what compiler was used to compile the code, but I would like to know for sure.
Bonus question: How does the compiler/language determine what number to use for Command::LOGIN?
Before submitting this question, I have noticed some changes from say 3137527848 to 0 and back, so it is obviously not valid to rely on it not changing. I am still curious about how this number is determined, and how or why that number is changing.
From the C++11 Standard (or rather, n3485):
[dcl.enum]/2
If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.
Additionally, [expr.static.cast]/9
A value of a scoped enumeration type can be explicitly converted to an integral type. The value is unchanged if the original value can be represented by the specified type.
I think it's obvious that the values of the enumerators can be represented by uint32_t; if they weren't, [dcl.enum]/5 says "if the initializing value of an enumerator cannot be represented by the underlying type, the program is ill-formed."
So as long as you use the underlying type for conversion (either explicitly or via std::underlying_type<Command>::type), the value of those enumerators are fixed as long as you don't add any enumerators before them (in the same enumeration) or alter their order.
As Nicolas Louis Guillemo pointed out, be aware of possible different endianness when transferring the value.
If you assign explicit integer values to your enum constants then you are guaranteed to always have the same value when converting to the integer type.
Just do something like the following:
enum class Command : uint32_t {
LOGIN = 12,
MESSAGE = 46,
JOIN_CHANNEL = 5,
PART_CHANNEL = 0,
INVALID = 42
};
If you don't specify any values explicitly, the values are set implicitly, starting from zero and increasing by one with each move down the list.
Quoting from draft n3485:
[dcl.enum] paragraph 2
The enumeration type declared with an enum-key of only enum is an
unscoped enumeration, and its enumerators are unscoped enumerators.
The enum-keys enum class and enum struct are semantically equivalent;
an enumeration type declared with one of these is a scoped
enumeration, and its enumerators are scoped enumerators. [...] The
identifiers in an enumerator-list are declared as constants, and can
appear wherever constants are required. An enumerator-definition with
= gives the associated enumerator the value indicated by the constant-expression. If the first enumerator has no initializer, the
value of the corresponding constant is zero. An
enumerator-definition without an initializer gives the enumerator the
value obtained by increasing the value of the previous enumerator by
one.
The drawback of relying on this, is that if the list order somehow changes in the future, then your code might silently break, so I would advise you be explicit.
Command::LOGIN will always be 0 as long as it's the first enum in the list. Just be careful with the rest of the enums, because they will have different binary representations based on if the computer is using big endian or little endian.

Resources