我试图在我的程序中使用与底层类型相当的范围枚举,但以下代码不起作用。是因为我使用的编译器(VC11)中的C ++ 11标准支持不佳,还是因为代码违反了C ++ 11标准中的一些规则?在后一种情况下,哪些规则正在被打破(欢迎参考具体的标准条款)?
#include <type_traits>
enum class Test: short int { A,B,C };
template<typename E> bool operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E> bool operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
int main()
{
short int x = 123;
x != Test::B; // compilation error
}
这就是我认为我的代码应该符合C ++ 11的原因。引用C ++ 11标准(14.8.3.1):
对于每个函数模板,如果参数推导和检查成功,则为模板参数 (推导和/或显式)用于合成单个函数模板的声明 专门化,添加到候选函数集中以用于重载决策。如果,对于给定的函数模板,> gt;参数推导失败,则不会向该模板的&gt;候选函数集添加此类函数。
EDIT。我的代码不符合C ++ 11(感谢Vaughn Cato和Andy Prowl的解释)。替代工作代码在Andy Prowl的答案中提供。
P.S。毕竟我最终使用命名空间制作了无范围的枚举:
namespace Test_ {
enum Test { A,B,C };
};
using Test_::Test;
namespace Test2_ {
enum Test2 { Z,Y,B };
};
using Test2_::Test2;
答案 0 :(得分:4)
当相应的参数不枚举时,您可以使用SFINAE来排除比较运算符签名的实例化(以及std::underlying_type<T>
的实例化):
#include <type_traits>
template<typename E,
typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
bool operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E,
typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
bool operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
这是live example。
修改强>
由于VC11似乎缺乏对函数模板模板参数的默认参数的支持,因此这是一个替代解决方案:
template<typename E>
typename std::enable_if<std::is_enum<E>::value, bool>::type
operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E>
typename std::enable_if<std::is_enum<E>::value, bool>::type
operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
当然是live example。
答案 1 :(得分:1)
C ++ 11标准的第14.8.2节第8段规定:
如果替换导致无效的类型或表达式,则类型推导失败。无效的类型或表达式 如果使用替换参数编写,则会形成错误的。 [注意:访问检查完成为 替代过程的一部分。 - 结束注释] 仅在上下文中使用无效的类型和表达式 函数类型及其模板参数类型可能导致演绎失败。 [注意:评估 替换类型和表达式可能导致副作用,例如类模板的实例化 专业化和/或功能模板专业化,隐式定义函数的生成等。 这种副作用不在“直接背景”中,并且可能导致程序形成不良。 - 结束 注意]
在您的情况下,实例化underlying_type
会导致失败,但不会导致直接上下文,因此它不是类型扣除失败,因此SFINAE不适用。