Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an out-of-range enum conversion produce a value outside the underlying type?

Consider the following:

#include <iostream>

enum class E : bool { A, B };

void foo(E e)
{
    switch(e)
    {
    case E::A: break;
    case E::B: break;
    default: std::cout << "aha\n";
    }
}

int main()
{
    foo( static_cast<E>(3) );
}

My question is: Can the default case be triggered, i.e. this program generates output?

The tricky point in N3936 seems to be the specification of static_cast when converting an out-of-range integer to enumeration type, [expr.static.cast]/10:

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values. Otherwise, the resulting value is unspecified (and might not be in that range).

The bolded text does not explicitly say that the value must still be within the range of the underlying type, but I am wondering if it were intended that it did.

like image 544
M.M Avatar asked Nov 09 '15 11:11

M.M


People also ask

What does do not cast an out of range enumeration value?

Enumerations in C++ come in two forms: scoped enumerations in which the underlying type is fixed and unscoped enumerations in which the underlying type may or may not be fixed.

Can enum values be changed?

4) Enum constants are implicitly static and final and can not be changed once created.

Can enum be override?

You cannot override enums, and C# does not support return type covariance.

What is the underlying type of an enum?

Each enum type has a corresponding integral type called the underlying type of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the enum_base is present, it explicitly declares the underlying type.

What is out-of-range enum in C++?

C++ Value of an out-of-range enum. Example. If a scoped enum is converted to an integral type that is too small to hold its value, the resulting value is unspecified. Example: Also, if an integer is converted to an enum and the integer's value is outside the range of the enum's values, the resulting value is unspecified.

What happens when an integer is converted to an enum?

Also, if an integer is converted to an enum and the integer's value is outside the range of the enum's values, the resulting value is unspecified. Example: However, in the next example, the behavior is not unspecified, since the source value is within the range of the enum, although it is unequal to all enumerators:

What happens if enum values are too small to hold?

If a scoped enum is converted to an integral type that is too small to hold its value, the resulting value is unspecified. Example: enum class E { X = 1, Y = 1000, }; // assume 1000 does not fit into a char char c1 = static_cast<char> (E::X); // c1 is 1 char c2 = static_cast<char> (E::Y); // c2 has an unspecified value

Is the behavior of an enum always unspecified?

However, in the next example, the behavior is not unspecified, since the source value is within the range of the enum, although it is unequal to all enumerators: Here s will have the value 3, and be unequal to ONE, TWO, and FOUR.


1 Answers

I think [expr.static.cast]/10 answers this. In the current working draft, this reads:

A value of integral or enumeration type can be explicitly converted to a complete enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the behavior is undefined.

In other words, your program has undefined behaviour, since the range of an enumeration type with fixed underlying type (in your case: bool) is the range of that type.

The change from your quote was affected by the resolution of CWG1766 (issues link); note that the issue is recognized as a defect (so you should forget the original wording).

like image 85
Kerrek SB Avatar answered Sep 30 '22 03:09

Kerrek SB