24

Is there a type trait, or is it possible to write a type trait is_scoped_enum<T> such that:

  • if T is a scoped enumeration, is_scoped_enum<T>::value is true and
  • if T is any other type, is_scoped_enum<T>::value is false
7
  • By scoped enum, you meant C++11's enum? Commented May 23, 2012 at 17:17
  • 3
    @Nawaz: A scoped enum is what an enum class is called in C++11, yes. Commented May 23, 2012 at 17:18
  • Just out of curiosity, what practical applications are there for this one? Commented May 24, 2012 at 18:43
  • 2
    @Xeo: I am overloading the bitwise operators for a set of scoped enumeration types. Commented May 24, 2012 at 21:08
  • bitbucket.org/martinhofernandes/wheels/src/353fc67489dc/include/… Commented May 24, 2012 at 21:15

2 Answers 2

38

I think testing if it is an enum and not implicitly convertible to the underlying type should do the trick.

template <typename T, bool B = std::is_enum<T>::value>
struct is_scoped_enum : std::false_type {};

template <typename T>
struct is_scoped_enum<T, true>
: std::integral_constant<bool,
    !std::is_convertible<T, typename std::underlying_type<T>::type>::value> {};
Sign up to request clarification or add additional context in comments.

7 Comments

Better use std::underlying_type<T> instead of int. An enum class in C++11 can base on something not convertible to int.
@KennyTM: What type? C++11 §7.2/2 states "The enum-base shall name an integral type;" is there an integral type not convertible to int?
@JamesMcNellis: You're correct. Sorry for confusion. (I was thinking of is_convertible doing implicit conversion.)
This is a good solution, except that with the latest edit, the logic is now backwards: ::value is true if T is an unscoped enumeration. :-)
@Excelcius It's worse than the possibility of getting an error or not: using std::underlying_type with a non-enum type is undefined behaviour, which requires no diagnostic, so the compiler need not report the misuse, which then gives your program UB. I didn't look at common implementations but presume the Standard allows UB to facilitate easier implementation in valid use cases.
|
0

C++23 will be providing is_scoped_enum which can be used once it gets implemented. See this link for documentation: is_scoped_enum. I don't think clang supports this yet (see clang status for the latest info of what features are supported).

For now I am using a slightly simplified version of the answer above (using _v and _t) as well as an implementation of is_underlying:

// C++ 23 should include 'is_scoped_enum' and 'to_underlying' so the following
// code can be removed:

template<typename T, bool B = std::is_enum_v<T>>
struct is_scoped_enum : std::false_type {};

template<typename T>
struct is_scoped_enum<T, true>
  : std::integral_constant<
      bool, !std::is_convertible_v<T, std::underlying_type_t<T>>> {};

template<typename T>
inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;

template<typename T, std::enable_if_t<is_scoped_enum_v<T>, int> = 0>
[[nodiscard]] constexpr auto to_underlying(T x) noexcept {
  return static_cast<std::underlying_type_t<T>>(x);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.