如何让IntWrapper子类仅支持同类型对象的比较运算符?
解决同类型子类比较限制的CRTP方案
好问题!要实现仅允许同类型子类(如Foo和Bar)之间进行比较,同时保留IntWrapper中比较运算符的核心逻辑,**奇异递归模板模式(CRTP)**是最优雅的解决方案,完全符合你的需求。
问题根源
你当前的代码中,Foo和Bar可以跨类型比较的原因是:所有比较运算符的参数都是IntWrapper类型,而public继承允许派生类对象被隐式"切片"为基类对象,因此foo >= bar会被转换成static_cast<IntWrapper>(foo) >= static_cast<IntWrapper>(bar),从而绕过类型检查。
解决方案:CRTP改造IntWrapper
我们将IntWrapper改为模板类,让它接收派生类作为模板参数,这样就能让每个子类的比较运算符仅接受自身类型的参数:
// CRTP基类,模板参数为派生类 template <typename Derived> struct IntWrapper { protected: int value; public: explicit IntWrapper() = default; explicit IntWrapper(const int value) : value(value) {} // 比较运算符仅接受同派生类类型的参数 bool operator< (const Derived& rhs) const { // 安全转换到基类,访问protected成员value return value < static_cast<const IntWrapper&>(rhs).value; } bool operator> (const Derived& rhs) const { return value > static_cast<const IntWrapper&>(rhs).value; } bool operator<=(const Derived& rhs) const { return value <= static_cast<const IntWrapper&>(rhs).value; } bool operator>=(const Derived& rhs) const { return value >= static_cast<const IntWrapper&>(rhs).value; } bool operator==(const Derived& rhs) const { return value == static_cast<const IntWrapper&>(rhs).value; } explicit operator int() const { return value; } };
然后修改子类的继承方式,将自身作为模板参数传递给IntWrapper:
struct Foo : IntWrapper<Foo> { using IntWrapper<Foo>::IntWrapper; // 继承基类构造函数,保持原有写法 }; struct Bar : IntWrapper<Bar> { using IntWrapper<Bar>::IntWrapper; };
效果验证
现在尝试跨类型比较:
const Foo foo(1); const Bar bar(2); bool b = foo >= bar; // 编译错误!找不到匹配的operator>=
编译器会报错,因为Foo的operator>=只接受const Foo&类型的参数,而Bar无法隐式转换为Foo,完美实现了你的需求。
额外优势
- 所有比较逻辑仍集中在IntWrapper中,子类无需重复实现
- 保留了
explicit构造函数和int转换运算符的原有行为 - 类型检查在编译期完成,没有运行时开销
如果你还需要直接使用IntWrapper本身进行比较,可以添加一个非模板的版本:
// 直接使用的IntWrapper类,继承自CRTP基类 struct IntWrapperSelf : IntWrapper<IntWrapperSelf> { using IntWrapper<IntWrapperSelf>::IntWrapper; };
这样IntWrapperSelf对象也只能和同类型比较,保持一致性。
内容的提问来源于stack exchange,提问作者c.bear
相关产品推荐
相关产品推荐

