Old code:
# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
  template<typename _Tp>
    struct is_scoped_enum
    : bool_constant<__is_scoped_enum(_Tp)>
    { };
# else
  template<typename _Tp>
    struct is_scoped_enum
    : false_type
    { };

  template<typename _Tp>
    requires __is_enum(_Tp)
    && requires(remove_cv_t<_Tp> __t) { __t = __t; } // fails if incomplete
    struct is_scoped_enum<_Tp>
    : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
    { };
# endif


New code:
# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
  template<typename _Tp>
    struct is_scoped_enum
    : bool_constant<__is_scoped_enum(_Tp)>
    { };
# else
  template<typename _Tp>
    struct is_scoped_enum
    : false_type
    { };


  template<typename _Tp>
    requires __is_enum(_Tp)
    && requires { sizeof(_Tp); } // fails if incomplete
    struct is_scoped_enum<_Tp>
    : bool_constant<!requires(int __i) { __i = _Tp { }; }>
    { };
# endif


Easy to verify:
struct S { operator int() { return 4; } };
//enum E; // not legal.
enum E {};
enum Ei : int;
enum class CE;
enum U { Val = is_scoped_enum<U>::value };
static_assert(not is_scoped_enum<int*>::value);
static_assert(not is_scoped_enum<nullptr_t>::value);
static_assert(not is_scoped_enum<S>::value);
static_assert(not is_scoped_enum<E>::value);
static_assert(not is_scoped_enum<Ei>::value);
static_assert(is_scoped_enum<CE>::value);
static_assert(not is_scoped_enum<U>::value);

Reply via email to