【问题标题】:C++11 type trait to differentiate between enum class and regular enum区分枚举类和常规枚举的 C++11 类型特征
【发布时间】:2013-03-13 05:50:39
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 真正的问题是您使用的是va_args 而不是std::initializer_list 和/或可变参数模板。
  • 感谢您的提示,但我有 va_list 因为我正在使用 C 接口。
  • @Sam:我的回答能解决你的问题吗?
  • @AndyProwl:完美的答案,正是我想要的!

标签: c++ templates c++11 variadic variadic-functions


【解决方案1】:

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

#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!");
}

这是live example

致谢:

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

【讨论】:

  • +1,但有一个警告:它只有在某个枚举类E 的作者没有定义他自己的operator+(int,E) 时才有效。通过添加void dummy(int) 并使用decltype(dummy(std::declval&lt;E&gt;())) 来修复它。
  • @DanielFrey:好点。实际上,我可以使用不同的运算符,例如 ^,以减少干扰用户定义的运算符重载的可能性
  • @AndyProwl: 或者调用一个接受int的函数。
  • 测试到int的转换,据我所知,它不能由用户提供。
  • @AndyProwl:现在做最后一次编辑并从std::integral_constant 派生而不是这个90 年代的static const bool value = ...-thingy。 ;)
【解决方案2】:

似乎从 C++23 开始,@AndyProwl 提供的解决方案类似的解决方案将可从type_traits 获得

#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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 2012-09-16
    相关资源
    最近更新 更多