我正在使用 CRTP 向类提供依赖于模板参数的函数添加,在本例中添加operator +
and operator +=
,使用模板类ImplAdd
。对于前者,应该对两个参数执行隐式转换,这意味着我必须使用类内友元运算符,如下所示:
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;
}
};
这是必需的,因为实际继承自的类ImplAdd
定义常量值和这些常量的唯一值类型,就像作用域枚举一样。
//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){}
};
从我的角度来看,以下代码现在应该可以轻松编译,但事实并非如此。
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;
}
对于标有 C2676 的两行,将打印以下错误消息:
error C2676: binary '+' : 'const MyEnum::ValueT' does not define this operator or a conversion to a type acceptable to the predefined operator
我究竟做错了什么?使用将运算符定义为类内友元不是在两个参数上启用隐式转换的常见方法吗?如果没有的话,在这种情况下我该怎么办?