Skip to content

Latest commit

 

History

History
136 lines (96 loc) · 3.95 KB

200.md

File metadata and controls

136 lines (96 loc) · 3.95 KB
Info

Example

enum class scoped_enum { };
static_assert(std::is_scoped_enum<scoped_enum>{});

enum class scoped_enum_type : int { };
static_assert(std::is_scoped_enum<scoped_enum_type>{});

enum not_scoped_enum { };
static_assert(not std::is_scoped_enum<not_scoped_enum>{});

enum not_scoped_enum_type : int { };
static_assert(not std::is_scoped_enum<not_scoped_enum_type>{});

https://godbolt.org/z/j1rc8c

Puzzle

  • Can you implement scoped_enum and any_enum concepts to constrain foo overloads accordingly?
/*TODO - scoped_num, any_enum*/

using std::literals::string_view_literals::operator""sv;

constexpr auto foo(scoped_enum auto...) { return "scoped enums"sv; }
constexpr auto foo(any_enum auto...)    { return "any enums"sv; }
constexpr auto foo(auto...)             { return "..."sv; }

enum E { V1 };
enum ET : int { V2 };
enum class SEC : int { V3 };
enum struct SES : int { V4 };
enum : int { V5 };

static_assert("scoped enums"sv == foo(SEC{}));
static_assert("scoped enums"sv == foo(SEC::V3));
static_assert("scoped enums"sv == foo(SEC::V3, SES::V4));
static_assert("scoped enums"sv == foo(SEC::V3, SES::V4, SES{}, SES{}));

static_assert("any enums"sv == foo(E{}));
static_assert("any enums"sv == foo(E{}, ET::V2));
static_assert("any enums"sv == foo(V5, ET::V2, E{}));
static_assert("any enums"sv == foo(E{}, E::V1, V1, V5));

static_assert("..."sv == foo(0));
static_assert("..."sv == foo(0, V5));
static_assert("..."sv == foo(0, V1, E::V1, SEC::V3, SES::V4));

https://godbolt.org/z/s7ca5r

Solutions

void call_with_integer(int x) {};

template <typename T>
concept scoped_enum = std::is_enum_v<T> and not requires { call_with_integer(T{}); };

template <typename T>
concept any_enum = std::is_enum_v<T> and not scoped_enum<T>;

https://godbolt.org/z/GeEGrh

namespace detail {
    template<typename T>
    concept enumeration = std::is_enum_v<T>;

    template<typename T>
    concept integer_convertible = std::convertible_to<T, int>;
}

template<typename TEnum>
concept scoped_enum = detail::enumeration<TEnum> and not detail::integer_convertible<TEnum>;

template<typename TEnum>
concept any_enum = detail::enumeration<TEnum> and detail::integer_convertible<TEnum>;

https://godbolt.org/z/95EaP9

template <typename... Ts>
concept any_enum = (std::is_enum_v<Ts> and ...);

template <typename... Ts>
concept scoped_enum = any_enum<Ts...> and
    (not std::is_convertible_v<Ts, std::underlying_type_t<Ts>> and ...);

template <typename... Ts>
constexpr auto foo(Ts...) requires scoped_enum<Ts...> { return "scoped enums"sv; }
template <typename... Ts>
constexpr auto foo(Ts...) requires any_enum<Ts...> { return "any enums"sv; }
constexpr auto foo(auto...) { return "..."sv; }

https://godbolt.org/z/nfMG8W

template<class T> using is_scoped_enum =
  std::bool_constant<std::is_enum_v<T> and not std::is_convertible_v<T, std::underlying_type_t<T>>>;
template<class T> concept scoped_enum = is_scoped_enum<T>::value;
template<class T> concept any_enum = std::is_enum<T>::value and not is_scoped_enum<T>::value;

https://godbolt.org/z/xWYjT1

template <typename T> concept any_enum = std::is_enum_v<T> && std::is_convertible_v<T, std::underlying_type_t<T>>;
template <typename T> concept scoped_enum = std::is_enum_v<T> && !std::is_convertible_v<T, std::underlying_type_t<T>>;

https://godbolt.org/z/68M7jT

template<typename T>
concept scoped_enum = std::is_enum_v<T> and not std::is_convertible_v<T, std::underlying_type_t<T>>;

template<typename T>
concept any_enum = std::is_enum_v<T> and std::is_convertible_v<T, std::underlying_type_t<T>>;

https://godbolt.org/z/xnPh3n