在编写允许类提供重载的 CRTP 模板时operator+
基于模板参数,我发现如果类内友元运算符的参数都不属于它定义的类的类型,则该运算符似乎不会参与重载决策。
煮沸:
enum class FooValueT{
zero, one, two
};
class Foo{
FooValueT val_;
public:
Foo(FooValueT x) : val_(x){};
Foo& operator+=(Foo other){
val_ = (FooValueT)((int)val_ + (int)other.val_);
return *this;
}
//overload for Foo+Foo, FooValueT+Foo and Foo+FooValueT
friend Foo operator+(Foo lhs, Foo rhs){
Foo ret = lhs;
return ret += lhs;
}
//explicit overload for FooValueT+FooValueT
friend Foo operator+(FooValueT lhs, FooValueT rhs){
return (Foo)lhs + (Foo)rhs;
}
};
看起来有点多余,但是很有必要Foo my = FooValueT::one + FooValueT::zero;
应该是一个有效的表达式,如果没有一个参数具有类类型,则它们不会隐式转换,如中所述这个答案我之前的一个问题。
尽管付出了所有这些努力,以下代码仍无法编译:
int main(int argc, char* argv[])
{
Foo my = FooValueT::zero;
my += FooValueT::one;
my = Foo(FooValueT::zero) + FooValueT::two;
my = FooValueT::zero + Foo(FooValueT::two);
my = FooValueT::zero + FooValueT::two; //error C2676
return 0;
}
错误信息是:
error C2676: binary '+' : 'FooValueT' does not define this operator or a conversion to a type acceptable to the predefined operator
一旦我将运算符完全移出类,或者将其声明为友元但将其定义在类之外,这个问题就解决了。两者似乎都不是可行的选择Foo
是一个要派生的模板类。
据我所知,上面的课堂朋友定义operator+(ValueT,ValueT)
应该创建一个自由函数,就像这个定义一样:
class Foo{
/*All the stuff you saw previously*/
friend Foo operator+(FooValueT lhs, FooValueT rhs);
};
Foo operator+(FooValueT lhs, FooValueT rhs){
return (Foo)lhs + (Foo)rhs;
}
我这里哪里出错了?与常规自由友元函数相比,函数的类内友元定义是否会改变重载解析规则?