C ++ 14草案n4140读取
T
应为枚举类型
代表template <class T> struct underlying_type
。
写下来有多糟糕
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>
T
可以是任意类型吗?我是否会进入UB并且编译器会删除我的$ HOME(因为语言律师说“任何事情都可以在UB下发生”)?
答案 0 :(得分:4)
我会踏上UB [...]
技术上,是的。但实际上,它只是不会为非枚举类型编译。当你写:
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>;
^^^^^^^^^^^^^^^^^^^^^^^^^
在 conditional
模板可以实例化之前,必须对评估该模板参数。这相当于在函数体开始之前必须调用的所有函数参数。对于非枚举类型,underlying_type<T>
不完整(确定它在标准中指定为未定义但是合理),因此没有underlying_type_t
。因此实例化失败了。
在这种情况下,您需要做的是延迟实例化:
template <class T> struct tag { using type = T; };
typename std::conditional_t<
std::is_enum<T>::value,
std::underlying_type<T>,
tag<foo>>::type;
现在,我们的conditional
而非选择类型正在选择元功能! underlying_type<T>::type
只会被T
实例化为枚举。我们还必须包装foo
以将其转换为元函数。
这是一种常见的模式,在Boost.MPL中称为eval_if
是一个特殊的东西,它看起来像:
template <bool B, class T, class F>
using eval_if_t = typename std::conditional_t<B, T, F>::type;
请注意,我们都使用conditional_t
和 ::type
。