C++ 11类型特征,用于区分枚举类和常规枚举

Sam*_*Sam 18 c++ templates variadic variadic-functions c++11

我正在编写一个类似于boost :: promote的促销模板别名,但是对于C++ 11.这样做的目的是在从varidic函数检索参数时避免警告.例如

template <typename T>
std::vector<T> MakeArgVectorV(int aArgCount, va_list aArgList)
{
    std::vector<T> args;
    while (aArgCount > 0)
    {
        args.push_back(static_cast<T>(va_arg(aArgList, Promote<T>)));
        --aArgCount;
    }
    return args;
}
Run Code Online (Sandbox Code Playgroud)

Promote模板别名在可变参数的默认参数提升之后提升类型:1)小于int的整数被提升为int 2)float被提升为double

我的问题是可以提升标准C++枚举,但不提升C++ 11枚举类(编译器不会生成警告).我希望Promote使用常规枚举但忽略C++ 11枚举类.

如何区分我的Promote模板别名中的枚举类和枚举?

And*_*owl 28

这是一个可能的解决方案:

#include <type_traits>

template<typename E>
using is_scoped_enum = std::integral_constant<
    bool,
    std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
Run Code Online (Sandbox Code Playgroud)

该解决方案利用了C++ 11标准的第7.2/9段中指定的范围和未范围枚举之间的行为差​​异:

枚举器的值或未范围的枚举类型的对象通过整数提升(4.5)转换为整数.[...]请注意,没有为作用域枚举提供此隐式枚举到int转换.[...]

以下是如何使用它的演示:

enum class E1 { };
enum E2 { };
struct X { };

int main()
{
    // Will not fire
    static_assert(is_scoped_enum<E1>::value, "Ouch!");

    // Will fire
    static_assert(is_scoped_enum<E2>::value, "Ouch!");

    // Will fire
    static_assert(is_scoped_enum<X>::value, "Ouch!");
}
Run Code Online (Sandbox Code Playgroud)

这是一个实例.

致谢:

感谢Daniel Frey指出我之前的方法只有在没有用户定义的重载时才会起作用operator +.

  • +1,但有一个洞穴:它只有在某些枚举类`E`的作者没有**定义他自己的`operator +(int,E)`时才有效.通过添加`void dummy(int)`并使用`decltype(dummy(std :: declval <E>()))来修复它. (3认同)