std::underlying_type

< cpp‎ | types
 
 
 
Type support
Basic types
Fundamental types
Fixed width integer types (C++11)
Numeric limits
C numeric limits interface
Runtime type information
Type traits
Type categories
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Type properties
(C++11)
(C++11)
(C++14)
(C++11)
(C++11)(until C++20)
(C++11)(deprecated in C++20)
(C++11)
Type trait constants
Metafunctions
(C++17)
Endian
(C++20)
Constant evaluation context
Supported operations
Relationships and property queries
(C++11)
(C++11)
Type modifications
(C++11)(C++11)(C++11)
Type transformations
(C++11)
(C++11)
(C++17)
underlying_type
(C++11)
(C++11)(until C++20)(C++17)
 
Defined in header <type_traits>
template< class T >
struct underlying_type;
(since C++11)

If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.

Otherwise, the behavior is undefined.

(until C++20)

Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed.

(since C++20)

Member types

Name Definition
type the underlying type of T

Helper types

template< class T >
using underlying_type_t = typename underlying_type<T>::type;
(since C++14)

Notes

Each enumeration type has an underlying type, which can be

1. Specified explicitly (both scoped and unscoped enumerations)

2. Omitted, in which case it is int for scoped enumerations or an implementation-defined integral type capable of representing all values of the enum (for unscoped enumerations)

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
LWG 2396 C++11 incomplete enumeration types were allowed complete enumeration type required

Example

#include <iostream>
#include <type_traits>
 
enum e1 {};
enum class e2: int {};
 
int main() {
    bool e1_type = std::is_same<
        unsigned
       ,typename std::underlying_type<e1>::type
    >::value; 
 
    bool e2_type = std::is_same<
        int
       ,typename std::underlying_type<e2>::type
    >::value;
 
    std::cout
    << "underlying type for 'e1' is " << (e1_type?"unsigned":"non-unsigned") << '\n'
    << "underlying type for 'e2' is " << (e2_type?"int":"non-int") << '\n';
}

Output:

underlying type for 'e1' is unsigned
underlying type for 'e2' is int