While writing a CRTP template that enables classes to provide overloads for operator+
based on template arguments, I found that an in-class friend operator doesn't seem to participate in overload resolution if none of it's arguments is of the type of the class it was defined in.
Boiled down:
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;
}
};
Looks a bit excessive, but is necessary since Foo my = FooValueT::one + FooValueT::zero;
should be a valid expression and if none of the arguments has class-type, they are not implicitly converted, as explained in this answer to a previous question of mine.
Despite all this effort, the following code does not compile:
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;
}
The error message is:
error C2676: binary '+' : 'FooValueT' does not define this operator or a conversion to a type acceptable to the predefined operator
This problem resolves once I either move the operator out of the class completely, or declare it as a friend but define it outside the class. Neither of both seem to be viable options when Foo
is a template class that is to be derived from.
As far as I know, the above in-class friend definition of operator+(ValueT,ValueT)
should create a free function, just as this definition would:
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;
}
Where am I going wrong here? Does in-class friend definition of functions change the rules of overload resolution compared to regular free friend functions?