如何将 `std::is_enum` 与未命名的 `enum` 一起使用?

Jos*_*eno 3 c++ enums types constraints type-traits

标题几乎是不言自明的。这是我的情况:

\n
#include <type_traits>\n\nclass C1{\n    enum{\n        c1 = 3\n    }\n}\n\nclass C2{\n    enum{\n        c2 = 10\n    }\n}\n\ntemplate<class C>\nclass C3{\n    void do_this();\n    void do_that();\n\n    void foo(){\n        if constexpr(std::is_enum<C::c1>::value){\n            do_this();\n        }\n        if constexpr(std::is_enum<C::c2>::value){\n            do_that();\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果我尝试编译它,我会收到错误

\n
error: type/value mismatch at argument 1 in template parameter list for \xe2\x80\x98template<class _Tp> struct std::is_enum\xe2\x80\x99\nnote: expected a type, got \xe2\x80\x98typename C::c1\xe2\x80\x99\n\nerror: type/value mismatch at argument 1 in template parameter list for \xe2\x80\x98template<class _Tp> struct std::is_enum\xe2\x80\x99\nnote: expected a type, got \xe2\x80\x98typename C::c2\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n

std::is_enum因此我的问题是:是否可以与未命名的一起使用enum

\n

Tur*_*ght 5

绝对可以std::is_enum与未命名的枚举一起使用。

当前的实现中只有 2 个问题需要解决:

  • std::is_enum<C::c1>::value-C::c1是数据成员,但std::is_enum需要类型模板参数。
    =>你需要在这里使用decltype(...),例如std::is_enum<decltype(C::c1)>::value
  • C::c1C如果没有名为 的成员,将导致替换失败c1
    解决这个问题的唯一方法是在替换失败不会导致程序格式错误的情况下执行此操作。
    因此,您可以使用 SFINAE 或(如果 C++20 可用)需要表达式

所以对于 C++20 这可以工作:

神箭示例

template<class T>
concept is_enum_value = std::is_enum_v<T>;

template<class C>
struct C3 {
    void foo() {
        if constexpr(requires { { C::c1 } -> is_enum_value; }) {
            do_this();
        }
        if constexpr(requires { { C::c2 } -> is_enum_value; }) {
            do_that();
        }
    }

    // ...
};
Run Code Online (Sandbox Code Playgroud)

如果C::c1C::c2是互斥的(即每个类都C具有其中之一c1c2两者都不存在 - 但绝不会同时c1存在两者),您可能会考虑使用尾随的 require 子句进行重载。c2foo

神箭示例

template<class C>
struct C3 {
    void foo() requires requires { { C::c1 } -> is_enum_value; } {
        // do_this implementation
    }
    void foo() requires requires { { C::c2 } -> is_enum_value; } {
        // do_that implementation
    }
};
Run Code Online (Sandbox Code Playgroud)

如果 C++20 不可用,您需要使用 SFINAE,这有点麻烦:

神箭示例

template<class T, class = void>
constexpr bool has_c1 = false;
template<class T>
constexpr bool has_c1<T, std::enable_if_t<std::is_enum_v<decltype(T::c1)>>> = true;

template<class T, class = void>
constexpr bool has_c2 = false;
template<class T>
constexpr bool has_c2<T, std::enable_if_t<std::is_enum_v<decltype(T::c2)>>> = true; 

template<class C>
struct C3 {
    void foo() {
        if constexpr(has_c1<C>) {
            do_this();
        }
        if constexpr(has_c2<C>) {
            do_that();
        }
    }

    // ...
};
Run Code Online (Sandbox Code Playgroud)