I am using CRTP to provide template-argument dependent addition of functions to a class, in this case the addition of operator +
and operator +=
, using the template class ImplAdd
. For the former, implicit conversions should be performed on both arguments, which means I have to use an in-class friend operator like this:
template<class Type, bool active>
struct ImplAdd{
virtual int get_val_() const = 0;
virtual void set_val_(int) = 0;
};
//if activated is true, the operators + and += will be defined
template<class Type>
class ImplAdd < Type, true > {
virtual int get_val_() const = 0;
virtual void set_val_(int) = 0;
Type* this_(){ return (Type*)this; }
public:
Type& operator +=(const Type& x){
set_val_(get_val_() + x.get_val_());
return *this_();
}
//This should enable conversions on the lefthand argument
friend Type& operator+(const Type& lhs, const Type& rhs){
Type ret = lhs;
return ret += rhs;
}
};
This is needed because classes that actually inherit from ImplAdd
define constant values and a unique value type for those constants, much like a scoped enum.
//by using true as the template argument, the operators + and += will be defined
class MyEnum : public ImplAdd<MyEnum, true>{
int get_val_() const override{
return (int)value;
}
void set_val_(int v) override{
value = (ValueT)v;
}
public:
enum class ValueT{
zero, one, two
};
private:
typedef int UnderlyingT;
ValueT value;
public:
static const ValueT zero = ValueT::zero;
static const ValueT one = ValueT::one;
static const ValueT two = ValueT::two;
MyEnum(ValueT x) : value(x){}
MyEnum(const MyEnum& other) : value(other.value){}
};
From my perspective, the following code should now easily compile, but it doesn't.
int main(int argc, char* argv[])
{
MyEnum my = MyEnum::zero; //works
my += MyEnum::one; //works
my = MyEnum(MyEnum::zero) + MyEnum::two; //works
my = MyEnum::zero + MyEnum(MyEnum::two); //ERROR C2676
my = MyEnum::zero + MyEnum::two; //ERROR C2676
MyEnum my2 = my + my; //works
return 0;
}
For both lines marked with C2676, the following error message is printed:
error C2676: binary '+' : 'const MyEnum::ValueT' does not define this operator or a conversion to a type acceptable to the predefined operator
What am I doing wrong? Isn't the use of defining an operator as an in-class friend the common way to enable implicit conversion on both arguments? If not, how can I do it in this case?