C++17如何为类int类型实现符合习惯用法的NaN算术运算
符合C++17习惯的实现方案
C++不允许直接修改原生类型或标准库类型的默认运算符行为,因此轻量强类型包装器是唯一符合规范且简洁的实现方案,一次实现即可同时覆盖int、std::chrono相关类型的需求,完全保留中缀运算符的使用习惯。
核心实现代码
首先定义通用模板类,所有NaN判断和运算符逻辑只需要写一次:
#include <limits> #include <chrono> #include <type_traits> template<typename T, T NanValue = std::numeric_limits<T>::max()> class NanAware { T m_value; public: // 构造函数,默认值为NaN constexpr NanAware(T value = NanValue) noexcept : m_value(value) {} // 显式转换为原始类型,避免意外隐式转换 constexpr explicit operator T() const noexcept { return m_value; } // 判断是否为NaN constexpr bool is_nan() const noexcept { return m_value == NanValue; } // 重载加法运算符 constexpr friend NanAware operator+(const NanAware& lhs, const NanAware& rhs) noexcept { if (lhs.is_nan() || rhs.is_nan()) return {}; return lhs.m_value + rhs.m_value; } // 重载减法运算符 constexpr friend NanAware operator-(const NanAware& lhs, const NanAware& rhs) noexcept { if (lhs.is_nan() || rhs.is_nan()) return {}; return lhs.m_value - rhs.m_value; } // 按需重载 +=、-= 等其他运算符 constexpr NanAware& operator+=(const NanAware& rhs) noexcept { *this = *this + rhs; return *this; } constexpr NanAware& operator-=(const NanAware& rhs) noexcept { *this = *this - rhs; return *this; } };
适配你需要的类型
只用给模板传入对应参数定义别名即可,不需要重复写运算逻辑:
// 带NaN的int类型,用int最大值作为NaN标记 using NanInt = NanAware<int>; // 带NaN的微秒级duration using NanMicroDuration = NanAware<std::chrono::microseconds>; // 带NaN的system_clock时间点,自定义NaN标记为最大微秒数对应的时间点 using NanTimePoint = NanAware< std::chrono::system_clock::time_point, std::chrono::system_clock::time_point{std::chrono::microseconds::max()} >;
使用示例
完全保留原生的中缀运算符写法,和你期望的Ruby使用体验一致:
NanInt a = 42; NanInt b; // 默认构造即为NaN NanInt c = a + b; // 运算结果自动为NaN if (c.is_nan()) { // 处理NaN分支 } // chrono类型使用方式完全相同 NanMicroDuration d1 = std::chrono::microseconds(100); NanMicroDuration d2; auto d3 = d1 - d2; // 结果为NaN
额外说明
- 该实现是零成本抽象,编译器会完全优化掉包装层,性能和原生类型完全一致
- 只要确保你选的NaN标记不在业务的正常取值范围内,就不会出现逻辑冲突
- 如果需要支持乘法、除法、比较等其他运算,只需要在模板类中按照相同逻辑重载对应运算符即可
内容的提问来源于stack exchange,提问作者Camille Goudeseune
相关产品推荐
相关产品推荐

