1. Revision History
1.1. Revision 1 - August 5th, 2019
- 
     Approved for Library Working Group in the Köln, Germany 2019 meeting! 
1.2. Revision 0 - June 17th, 2019
- 
     Initial release. 
2. Motivation
Many codebases write a version of a small utility function converting an enumeration to its underlying type. The reason for this function is very simple: applying 
Much of the same rationale is why this is Item 10 in Scott Meyers' Effective Modern C++. In Around Christmas of 2016, the number of these function invocations for C++ was around 200 including both to_underlying/to_underlying_type/toUtype (the last in that list being the way it was spelled by Scott Meyers). As of June 17th, 2019, the collective hits on GitHub and other source engines totals well over 1,000 hits, disregarding duplication from common base frameworks such as the realm mobile app database and more. The usefulness of this function appears in Loggers for enumerations, casting for C APIs, stream operations, and more.
We are seeing an explosive move and growth in usage of Modern C++ utilities, and the growth in this usage clearly indicates that the foresight and advice of Scott Meyers is being taken seriously by the full gamut of hobbyist to commercial software engineers. Therefore, it would seem prudent to make the spelling and semantics of this oft-reached-for utility standard in C++.
Typical casts can also mask potential bugs from size/signed-ness changes and hide programmer intent. For example, going from this code,
enum class ABCD { A = 0x1012 , B = 0x405324 , C = A & B }; // sometime later ... void do_work ( ABCD some_value ) { // no warning, no visual indication, // is this what the person wanted, // what was the original intent in this // 'harmless' code? internal_untyped_api ( static_cast < int > ( some_value )); } 
To this code:
#include <cstdint>// changed enumeration, underlying type enum class ABCD : uint32_t { A = 0x1012 , B = 0x405324 , C = A & B , D = 0xFFFFFFFF // !! }; // from before: void do_work ( ABCD some_value ) { // no warning, no visual indication, // is this what the person wanted, // what was the original intent in this // 'harmless' code? internal_untyped_api ( static_cast < int > ( some_value )); } 
is dangerous, but the 
Calling 
Doing it the right way is also cumbersome:
void do_work ( ABCD some_value ) { // will produce proper warnings, // but is cumbersome to type internal_untyped_api ( static_cast < std :: underlying_type_t < ABCD >> ( some_value )); } 
It is also vulnerable to the parameter’s type changing from an enumeration to another type that is convertible to an integer. Because it is still a 
void do_work ( OtherEnumeration value ) { // no warnings, no errors, ouch! internal_untyped_api ( static_cast < std :: underlying_type_t < ABCD >> ( some_value )); } 
We propose an intent-preserving function used in many codebases across C++ called 
3. Design
This makes it easy to find conversion points for "unsafe" actions, reducing search and refactoring area. It also puts the 
#include <utility>void do_work ( MyEnum value ) { // changes to match its value, // proper warnings for signed/unsigned mismatch, // and ease-of-use! internal_untyped_api ( std :: to_underlying ( some_value )); } 
4. Proposing Wording
The wording proposed here is relative to [n4800].
4.1. Proposed Feature Test Macro
The proposed library feature test macro is 
4.2. Intent
The intent of this wording is to introduce 1 function into the 
4.3. Proposed Library Wording
Append to §17.3.1 General [support.limits.general]'s Table 35 one additional entry:
Macro name Value __cpp_lib_to_underlying 202002L 
Add the following into §20.2.1 Header 
// [utility.underlying], to_underlying template < class T > constexpr std :: underlying_type_t < T > to_underlying ( T value ) noexcept ; 
Add a new section §20.2.7 Function template 
20.2.7 Function template[utility.underlying]to_underlying namespace std { template < typename T > constexpr std :: underlying_type_t < T > to_underlying ( T value ) noexcept ; } 1 Constraints:
shall satisfyT .std :: is_enum_v < T > 2 Returns:
.static_cast < std :: underlying_type_t < T >> ( value ) 
5. Acknowledgements
Thanks to Rein Halbersma for bringing this up as part of the things that would make programming in his field easier and the others who chimed in. Thanks to Walter E. Brown for the encouragement to Rein Halbersma to get this paper moving.