以下最小代码在g ++上编译,但不会在clang ++上编译:
template<class T>
T operator*(float a, const T& b)
{
return b * a;
}
struct A{
A operator*(float b) const
{
A a;
return a;
}
};
int main()
{
A a;
2.0f * a;
}
这是我得到的错误:
$ clang++ test.cpp
test.cpp:2:3: error: overloaded 'operator*' must have at least one parameter of
class or enumeration type
T operator*(float a, const T& b)
^
test.cpp:4:11: note: in instantiation of function template specialization
'operator*<float>' requested here
return b * a;
^
test.cpp:18:10: note: in instantiation of function template specialization
'operator*<A>' requested here
2.0f * a;
^
1 error generated.
Clang 3.5版。这段代码有效吗? Clang有错误吗?
答案 0 :(得分:2)
2.0f * a;
实例化::operator*<A>
。在该函数中,我们使用表达式b * a
,如果查看(简化)类型,则为A * float
。此时,编译器需要做出选择。那个*
应该是全局函数::operator*<float>
(因为右手参数是float
),还是应该是A::operator*
?对于我们人类来说,显然它应该是A::operator*
,但从编译器的角度来看,它并不是立即清楚的。
那么编译器做什么?它首先尝试查找可以使用的所有operator*
函数(之后,它会尝试确定要使用哪个函数)。 可以使用的operator*
个函数之一是::operator*<float>
。但等等,::operator*<float>
是什么?它是float *(float, const float&)
!我们做不到!你不能为基本类型重载运算符(想象一下,如果你重载int +(int, int)
就会出现混乱,这样你就可以让1 + 2
做一些与大家所期望的完全不同的事情。)
此时,该程序格式不正确。编译器甚至尝试实例化::operator*<float>
这一事实使整个程序无效。所以,我们能做些什么?告诉编译器到底要做什么:
template<class T>
T operator*(float a, const T& b)
{
// This prevents the compiler from instantiating ::operator*<float>
return b.operator*(a);
// The above is meant to illustrate how the fix needs to work: it needs
// to avoid instantiating ::operator*<float>. Other methods can be used
// (like SFINAE) that might be more elegant (check out Walter's answer
// in the duplicate: https://stackoverflow.com/a/18596809/1287251), but
// in the end any solution used must avoid ::operator*<float>.
}
struct A{
A operator*(float b) const
{
A a;
return a;
}
};
int main()
{
A a;
2.0f * a;
}
简而言之,回答这个问题:不,代码无效。您必须阻止编译器尝试实例化::operator*<float>
。
This is explained by @dyp in the comments和by @TemplateRex in the duplicate question。但是,在我理解他们的意思之前,我必须多次阅读他们的回答。我试图在这个答案中简化一些事情。如果我能改进它,请告诉我!