强类型指类型不能隐式越界,防单位混用需用struct/class封装+explicit构造函数+禁用隐式转换,推荐std::chrono;typedef/using别名无类型安全。

强类型不是“类型多”,而是“类型不能隐式越界”
在 C++ 里,int 和 double 算强类型,但 int 和 long 之间能隐式转换,单位混用风险就藏在这儿。比如把 ms(毫秒)直接赋给表示 s(秒)的变量,编译器不拦——这不是强类型失效,是没用对机制。
真正防单位混用,得靠用户定义类型(UDT),而不是依赖内置类型名。
- 别用
typedef int milliseconds;—— 它只是别名,和int完全兼容,milliseconds ms = 1000; int s = ms;依然合法 - 必须用
struct或class封装,禁用隐式转换:用explicit构造函数 + 删除operator int() - 推荐用
std::chrono:它本身就是基于强类型设计的,std::chrono::milliseconds和std::chrono::seconds不能直接相加,除非显式转换
std::chrono 是最省心的单位隔离方案
它把时间单位变成类型,不是数值标签。你写 auto t = 500ms;,t 的类型就是 std::chrono::milliseconds,不是 int。
常见错误现象:sleep_for(1000) 被误以为是毫秒(其实是纳秒?),或传 int 导致歧义。
立即学习“C++免费学习笔记(深入)”;
-
std::this_thread::sleep_for(1000ms)✅ 明确、安全、无需注释 -
std::this_thread::sleep_for(std::chrono::milliseconds(1000))✅ 同上,显式构造更清晰 -
std::this_thread::sleep_for(1000)❌ 编译失败(C++20 起),强制你说明单位 - 跨单位计算自动缩放:
5s + 500ms得到std::chrono::seconds类型,值为5(截断)或5500ms(取决于左侧类型)
自定义单位类型时,别漏掉 operator+= 和字面量支持
自己写 struct meters { double val; explicit meters(double v) : val(v) {} }; 只是起点。缺关键操作符,代码会很难用。
容易踩的坑:只重载 +,忘了 +=;或支持 meters + meters,但不支持 meters + double(其实不该支持)。
- 禁止
operator double()—— 否则又退回弱类型逻辑 - 提供
operator+=、operator-等,保持与内置类型的使用习惯一致 - 加字面量后缀(如
10.5_m):定义constexpr meters operator"" _m(long double v) { return meters{v}; } - 注意精度:用
double还是float?物理量通常要double,嵌入式可能需float或整型底座
模板别名(using)不是类型安全,只是语法糖
using meters = double; 和 typedef double meters; 效果一样:零运行时/编译时开销,也零类型防护。
有人觉得加了命名就“语义化”了,但编译器眼里它还是 double,meters m = 1.0; seconds s = m; 依然过编译。
- 所有基于
using/typedef的“单位别名”都属于伪强类型,仅利于阅读,不防错 - 若真要轻量封装,用
struct+[[nodiscard]]+explicit构造函数,哪怕只有一个double成员 - 性能影响极小:现代编译器对单成员
struct优化得和原生类型一样,ABI 也完全兼容
单位混用问题本质不是类型系统不够强,而是没把类型当契约来用。一个 struct 加两行 explicit 和 delete,比靠注释和人肉 review 可靠得多。最难的部分其实是说服团队——在所有数值字段前,都得想清楚它到底是什么单位,而不是先写 int 再补文档。








