如何在保留显式转换的前提下,弃用int到Duration的隐式转换?
解决方案
方案1:兼容C++14及以上,覆盖所有隐式转换场景
通过给隐式构造的重载添加无用默认占位参数避开同签名冲突,实现显式调用无警告、隐式转换触发警告的效果:
class Duration { int seconds; public: // 显式构造走这个分支,无警告 explicit Duration(int t_seconds) : seconds(t_seconds) { } // 仅隐式转换时会匹配到这个分支,触发弃用警告 [[deprecated("隐式转换int到Duration已弃用,请修改为显式构造")]] Duration(int t_seconds, void* = nullptr) : seconds(t_seconds) { } }; int main() { Duration t(30); // 正常编译无警告,优先匹配单参数explicit构造函数 t = 60; // 编译通过,触发弃用警告:无法使用explicit构造做隐式转换,只能匹配双参数重载 // 以下场景也会正确触发警告 // void test(Duration d) {} // test(60); // 触发警告 // Duration foo() { return 60; } // 触发警告 }
该方案原理:单参数的显式构造函数重载优先级更高,所有显式调用的场景都会优先走这个无警告的分支;需要隐式转换的场景下,explicit修饰的构造函数无法参与重载解析,只能匹配带默认占位参数的非explicit构造函数,触发deprecated警告。占位参数默认值为nullptr,不会影响实际使用,也不会额外增加内存或运行开销。
方案2:仅需处理赋值场景的轻量方案
如果你的场景中只有赋值操作存在隐式转换,不需要处理函数传参、返回值等其他隐式转换场景,可以直接重载int类型的赋值运算符,标记为弃用即可:
class Duration { int seconds; public: explicit Duration(int t_seconds) : seconds(t_seconds) { } [[deprecated("隐式转换int到Duration已弃用,请修改为显式构造后赋值")]] Duration& operator=(int t_seconds) { seconds = t_seconds; return *this; } }; int main() { Duration t(30); // 正常编译无警告 t = 60; // 编译通过,触发弃用警告 }
该方案实现简单,没有重载构造函数的额外逻辑,但是只能覆盖赋值场景,函数传参、值返回等其他隐式转换场景还是会直接编译报错。
C++20 更优雅的实现
如果可以使用C++20标准,可以用explicit(bool)特性实现更简洁的版本,不需要占位参数:
#include <type_traits> class Duration { int seconds; public: // 显式调用场景走这个分支,无警告 explicit Duration(int t_seconds) : seconds(t_seconds) { } // 仅隐式转换场景匹配该模板构造,触发警告 template<std::same_as<int> T> [[deprecated("隐式转换int到Duration已弃用,请使用显式构造")]] Duration(T t_seconds) : seconds(t_seconds) { } };
内容的提问来源于stack exchange,提问作者Nathan Pierson
相关产品推荐
相关产品推荐

