当我编译以下代码片段时,我得到了一个带有clang的编译器错误,但没有使用g ++ / MSVC:
#include <string>
template<typename T> struct Const {
explicit Const(T val) : value(val) {}
T value;
};
template<typename T> struct Var {
explicit Var(const std::string &n) : name(n) {}
std::string name;
};
template<typename L, typename R> struct Greater {
Greater(L lhs, R rhs) : left(lhs), right(rhs) {}
L left;
R right;
};
template<typename L>
Greater<L, Const<int> > operator > (L lhs, int rhs) {
return Greater<L, Const<int> >(lhs, Const<int>(rhs));
}
template<typename R>
Greater<Const<int>, R> operator > (int lhs, R rhs) {
return Greater<Const<int>, R>(Const<int>(lhs), rhs);
}
Var<double> d("d");
int main() {
d > 10;
return 0;
}
报告的错误如下:
error: overloaded 'operator>' must have at least one parameter of
class or enumeration type
Greater<Const<int>, R> operator > (int lhs, R rhs) {
^
./val.h:31:24: note: in instantiation of function template specialization
'operator><int>' requested here
Greater<Const<int>, R> operator > (int lhs, R rhs) {
^
1 error generated.
是关于未使用的运算符函数。相反,如果我写10&gt; d而不是d> 10,然后我得到关于其他运算符的相同错误&gt;功能。以上编译在gcc 4.4.6和VS2012下正常。我的错是什么?
谢谢。
答案 0 :(得分:7)
Clang是对的:运算符重载至少需要一个类或枚举类型参数,否则程序格式不正确(13.5 / 1)。要了解为什么会出现此错误,我们必须解析更多标准法律问题。
回想起名称查询,论证扣除和重载决议的三位一体。第一步找到两个重载的operator>
。第二步推导出每个版本的模板参数。您可能会认为第二次超载会成为SFINAE规则(14.8.2)的受害者,因此只有第一次超载才会存活到第三步。但是,没有替换失败(例如缺少嵌套的typedef),而是非法的构造(参见前面提到的13.5 / 1)。这本身就使得该计划形成不良(14.3 / 6)
6如果在模板专业化的实例化中使用template-argument会导致格式错误的构造,那么该程序就会形成错误。
在14.8.3中,提到对推断出的参数的这种检查在重载解析之前发生,因此你的首选运算符不可能被选中。
作为C ++ 03的解决方法,您可以在operator>
类模板中定义两个朋友非模板Var<T>
。这些将作为具有一个类类型参数的非模板函数注入到周围(全局,在此示例中)命名空间中,因此不应发生上述错误。
答案 1 :(得分:0)
我必须承认,我真的不知道为什么clang在这里抱怨,它看起来像一个bug(编译器的)。顺便说一下,clang 3.3也表现出这个问题。
您可以使用SFINAE来抑制它:
template<typename L>
typename std::enable_if<std::is_class<L>::value || std::is_enum<L>::value,
Greater<L, Const<int>>>::type
operator > (L lhs, int rhs) {
return Greater<L, Const<int> >(lhs, Const<int>(rhs));
}
template<typename R>
typename std::enable_if<std::is_class<R>::value || std::is_enum<R>::value,
Greater<Const<int>,R>>::type
operator > (int lhs, R rhs) {
return Greater<Const<int>, R>(Const<int>(lhs), rhs);
}
答案 2 :(得分:0)
这看起来像g ++和VS中的一个错误。在您的示例中,您的类型R
为int
(因为右侧操作数为int
)。然后,这将使函数Greater<Const<int>, R> operator > (int lhs, int rhs)
的签名与内置operator<
ints 的签名相同(参数)。请注意,在决定使用哪个operator>
时,它必须考虑两个模板(并尝试为每个模板分别推断类型):它不能只看其中一个并决定忽略另一个。