我正在编写类似于boost :: promote的促销模板别名,但是对于C ++ 11。 这样做的目的是在从varidic函数检索参数时避免警告。 e.g。
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枚举类(编译器不会生成警告)。我希望Promote能够使用常规枚举但忽略C ++ 11枚举类。
如何区分我的Promote模板别名中的枚举类和枚举?
答案 0 :(得分:23)
这是一个可能的解决方案:
#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 :(得分: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