C++中如何基于实例的模板类型重载函数
问题说明
我判断当前问题不属于「不指定类模板参数时模板类的模板成员函数特化」类问题的重复问题,相关参考内容理解门槛较高,若判断存在偏差还请谅解,目前暂未检索到其他高度匹配的相关问题。
核心疑问:是否存在可行方法,能够基于实例的模板类型重载对应函数?
使用场景
我实现了一个重载取模运算符的数值包装类,初始代码如下:
template <typename X> class Operand { private: X _val; public: Operand *operator% (const Operand &other_number) const { // 此处需要对float、double类型使用fmod,对整型类型使用原生%运算符 } };
我也考虑过通用兼容方案:将所有值强制转换为long double类型,调用fmod计算后再转回X类型,但该方案存在明显缺陷:
- 运行效率极低
- 实现方式笨拙
- 不符合C++语言惯用法
- 大概率存在潜在类型转换隐患
实现方案
不需要做复杂的全类模板特化,C标准库已经提供了编译期类型判断工具,可以零开销实现分支选择,根据项目使用的C标准选对应方案即可。
方案1:C++17及以上版本使用if constexpr(优先推荐)
这是最简洁、可读性最高的写法,分支判断在编译期完成,没有任何运行时开销:
#include <cmath> #include <type_traits> template <typename X> class Operand { private: X _val; public: Operand* operator% (const Operand& other_number) const { X calc_res; if constexpr (std::is_floating_point_v<X>) { // 浮点类型编译期选择fmod分支,不会生成冗余判断逻辑 calc_res = std::fmod(_val, other_number._val); } else { // 整型类型编译期选择原生%运算符分支 calc_res = _val % other_number._val; } // 注:原接口返回堆指针存在内存泄漏风险,更推荐直接返回Operand值类型 return new Operand(calc_res); } Operand(X val) : _val(val) {} };
方案2:C11/C14版本使用标签分发
如果项目使用的旧标准不支持C++17,可以通过标签分发实现等价的编译期分支效果,同样没有运行时损耗:
#include <cmath> #include <type_traits> template <typename X> class Operand { private: X _val; // 浮点类型分支实现 X mod_calc(const Operand& other, std::true_type) const { return std::fmod(_val, other._val); } // 整型类型分支实现 X mod_calc(const Operand& other, std::false_type) const { return _val % other._val; } public: Operand* operator% (const Operand& other_number) const { X calc_res = mod_calc(other_number, std::is_floating_point<X>{}); return new Operand(calc_res); } Operand(X val) : _val(val) {} };
补充提示:如果后续需要支持自定义数值类型,只需要扩展类型判断逻辑即可,不需要修改核心计算流程。
内容的提问来源于stack exchange,提问作者GDGiantDwarf
相关产品推荐
相关产品推荐

