28

我正在编写类似于 boost::promote 的促销模板别名,但适用于 C++11。这样做的目的是避免在从可变函数检索参数时出现警告。例如

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;
}

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

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

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

4

2 回答 2

43

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

#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>;

该解决方案利用了 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!");
}

这是一个活生生的例子

致谢:

感谢Daniel Frey指出我之前的方法只有在没有用户定义的operator +.

于 2013-03-23T11:40:37.353 回答
1

从 C++23 开始, type_traits提供了与@AndyProwl 提供的解决方案类似的解决方案

#include <type_traits>

enum E { a, b };
enum class Es { x, y, z };

std::is_scoped_enum_v<E>;  // False
std::is_scoped_enum_v<Es>; // True
于 2021-08-09T20:26:31.677 回答