Skip to content

Commit 372c2ee

Browse files
author
Michael Blome
committed
enums without enumerators
1 parent ed0e450 commit 372c2ee

1 file changed

Lines changed: 46 additions & 6 deletions

File tree

docs/cpp/enumerations-cpp.md

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,25 @@ enum [class|struct]
6262

6363
```
6464
// Forward declaration of enumerations (C++11):
65-
enum A : int; // non-scoped enum must have type specifiedenum class B; // scoped enum defaults to intenum class C : short;
65+
enum A : int; // non-scoped enum must have type specified
66+
enum class B; // scoped enum defaults to int but ...
67+
enum class C : short; // ... may have any integral underlying type
6668
```
6769

68-
#### Parameters
70+
## Parameters
6971
`identifier`
7072
The type name given to the enumeration.
7173

7274
`type`
7375
The underlying type of the enumerators; all enumerators have the same underlying type. May be any integral type.
7476

7577
`enum-list`
76-
Comma-separated list of the enumerators in the enumeration. Every enumerator or variable name in the scope must be unique. However, the values can be duplicated. In a unscoped enum, the scope is the surrounding scope; in a scoped enum, the scope is the `enum-list` itself.
78+
Comma-separated list of the enumerators in the enumeration. Every enumerator or variable name in the scope must be unique. However, the values can be duplicated. In a unscoped enum, the scope is the surrounding scope; in a scoped enum, the scope is the `enum-list` itself. In a scoped enum, the list may be empty which in effect defines a new integral type.
7779

7880
`class`
7981
By using this keyword in the declaration, you specify the enum is scoped, and an `identifier` must be provided. You can also use the `struct` keyword in place of `class`, as they are semantically equivalent in this context.
8082

81-
## Remarks
83+
## Enumerator scope
8284
An enumeration provides context to describe a range of values which are represented as named constants and are also called enumerators. In the original C and C++ enum types, the unqualified enumerators are visible throughout the scope in which the enum is declared. In scoped enums, the enumerator name must be qualified by the enum type name. The following example demonstrates this basic difference between the two kinds of enums:
8385

8486
```cpp
@@ -123,7 +125,7 @@ enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };
123125

124126
Then the values of `Diamonds`, `Hearts`, `Clubs`, and `Spades` are 5, 6, 4, and 5, respectively. Notice that 5 is used more than once; this is allowed even though it may not be intended. These rules are the same for scoped enums.
125127

126-
**Casting rules**
128+
## Casting rules
127129

128130
Unscoped enum constants can be implicitly converted to `int`, but an `int` is never implicitly convertible to an enum value. The following example shows what happens if you try to assign `hand` a value that is not a `Suit`:
129131

@@ -162,7 +164,45 @@ namespace ScopedEnumConversions
162164

163165
```
164166

165-
Notice that the line `hand = account_num;` still causes the error that occurs with unscoped enums, as shown earlier. It is allowed with an explicit cast. However, with scoped enums, the attempted conversion in the next statement, `account_num = Suit::Hearts;`, is no longer allowed without an explicit cast.
167+
Notice that the line `hand = account_num;` still causes the error that occurs with unscoped enums, as shown earlier. It is allowed with an explicit cast. However, with scoped enums, the attempted conversion in the next statement, `account_num = Suit::Hearts;`, is no longer allowed without an explicit cast.
168+
169+
## Enums with no enumerators (Visual Studio 2017 version 15.3 and later)
170+
By defining an enum (regular or scoped) with an explicit underlying type and no enumerators, you can in effect introduce a new integral type that has no implicit conversion to any other type. By using this type instead of its built-in underlying type, you can eliminate the potential for subtle errors caused by inadvertent implicit conversions.
171+
172+
173+
```cpp
174+
enum class byte : unsigned char { };
175+
```
176+
177+
The new type is an exact copy of the underlying type, and therefore has the same calling convention, which means it can be used across ABIs without any performance penalty. No cast is required when variables of the type are initialized by using direct-list initialization. The following example shows how to initialize enums with no enumerators in various contexts:
178+
179+
```cpp
180+
enum class byte : unsigned char { };
181+
182+
enum class E : int { };
183+
E e1{ 0 };
184+
E e2 = E{ 0 };
185+
186+
struct X
187+
{
188+
E e{ 0 };
189+
X() : e{ 0 } { }
190+
};
191+
192+
E* p = new E{ 0 };
193+
194+
void f(E e) {};
195+
196+
int main()
197+
{
198+
f(E{ 0 });
199+
byte i{ 42 };
200+
byte j = byte{ 42 };
201+
202+
// unsigned char c = j; // C2440: 'initializing': cannot convert from 'byte' to 'unsigned char'
203+
return 0;
204+
}
205+
```
166206

167207
## See Also
168208
[C Enumeration Declarations](../c-language/c-enumeration-declarations.md)

0 commit comments

Comments
 (0)