如何在CRTP模板中禁用拷贝赋值,仅允许引用接收generate返回值
问题根源
你之前的修改没有生效有两个核心原因:
DerivedSignal sig = DerivedSignal::generate()属于拷贝初始化语义,调用的是拷贝构造函数而非拷贝赋值运算符,你只删除赋值运算符自然不会拦截这个场景。- 你写的拷贝赋值运算符签名不符合标准:常规拷贝赋值运算符的返回值是左值引用,你返回值类型的声明和编译器默认生成的拷贝赋值签名不匹配,相当于没有删除默认的拷贝赋值运算符,自然不生效。
可行实现方案
你只需要在CRTP基类SignalT中同时删除拷贝构造、移动构造、拷贝赋值、移动赋值四个函数即可,同时将基类的构造函数设为protected权限,仅允许子类访问:
template <class tDerivedSignal, class tBridgeType, class tPayLoadType = void> class SignalT : public SignalSignatureT<tBridgeType> { protected: // 仅允许子类构造基类实例 SignalT() = default; public: // 删除拷贝/移动构造,直接拦截值接收的场景 SignalT(const SignalT&) = delete; SignalT(SignalT&&) = delete; // 删除拷贝/移动赋值,拦截已有对象赋值覆盖的场景 SignalT& operator=(const SignalT&) = delete; SignalT& operator=(SignalT&&) = delete; // ... 其余原有代码保持不变 static tDerivedSignal &generate(tPayLoadType &fPayLoad) { tDerivedSignal &rtnVal = Pool::reserve(); rtnVal.mPayLoad = fPayLoad; return rtnVal; } ... };
效果验证
修改后:
- 合法用法
DerivedSignal &sig = DerivedSignal::generate()可以正常编译运行,没有任何影响 - 非法用法
DerivedSignal sig = DerivedSignal::generate()会直接触发编译报错,提示拷贝构造函数已被删除,完全符合要求
内容的提问来源于stack exchange,提问作者Nilsie
相关产品推荐
相关产品推荐

