Index: include/type_traits =================================================================== --- include/type_traits +++ include/type_traits @@ -4700,12 +4700,18 @@ #ifdef _LIBCPP_UNDERLYING_TYPE -template -struct underlying_type +template ::value> +struct __impl_underlying_type { typedef _LIBCPP_UNDERLYING_TYPE(_Tp) type; }; +template +struct __impl_underlying_type<_Tp, false> { }; + +template +struct underlying_type : __impl_underlying_type<_Tp> { }; + #if _LIBCPP_STD_VER > 11 template using underlying_type_t = typename underlying_type<_Tp>::type; #endif Index: test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// type_traits + +// underlying_type + +#include + +int main(int, char**) +{ + // no `type` member indicates that `int` is not an enum + using t = std::underlying_type::type; // expected-error {{no type named 'type' in 'std::__1::underlying_type'}} + return 0; +} Index: test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp =================================================================== --- test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp +++ test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp @@ -27,6 +27,18 @@ enum F { W = UINT_MAX }; #endif // TEST_UNSIGNED_UNDERLYING_TYPE +template ::type> +std::true_type test_sfinae(int); + +template +std::false_type test_sfinae(...); + +template +constexpr bool test_sfinae_v() // This is a function so it is valid pre-c++14 +{ + return decltype(test_sfinae(0))::value; +} + int main(int, char**) { ASSERT_SAME_TYPE(int, std::underlying_type::type); @@ -49,6 +61,9 @@ ASSERT_SAME_TYPE(char, std::underlying_type_t); #endif // TEST_STD_VER > 11 #endif // TEST_STD_VER >= 11 + + static_assert(!test_sfinae_v(), "Not an enum"); + static_assert(test_sfinae_v(), "Is an enum"); return 0; } Index: www/cxx2a_status.html =================================================================== --- www/cxx2a_status.html +++ www/cxx2a_status.html @@ -139,7 +139,7 @@ P0339R6LWGpolymorphic_allocator<> as a vocabulary typeKona - P0340R3LWGMaking std::underlying_type SFINAE-friendlyKona + P0340R3LWGMaking std::underlying_type SFINAE-friendlyKonaComplete P0738R2LWGI Stream, You Stream, We All Stream for istream_iteratorKona P0811R3LWGWell-behaved interpolation for numbers and pointersKona P0920R2LWGPrecalculated hash values in lookupKona