<p>自定义字面量后缀必须以下划线开头,如 operator""_km;字符串字面量重载需 const char* + size_t 参数;数值字面量分整型(unsigned long long)、浮点(long double)分支;所有 constexpr 实现须纯编译期运算且加 inline 避免 ODR 问题。</p>

自定义字面量后缀必须带下划线
不加下划线的自定义后缀(比如 operator""s)是非法的——C++标准明确保留所有不以下划线开头的用户定义后缀给未来标准用。你写 operator""km,编译器会直接报错:error: user-defined literal suffixes not starting with '_' are reserved。
实操建议:
- 一律用
operator""_km、operator""_sec这种带前导下划线的形式 - 后缀名本身别用双下划线(如
_ _m),那是实现保留的 - 名字尽量短且可读,
_ms比_milliseconds更常用,也更安全(避免模板实例化膨胀)
字符串字面量自定义后缀要接 const char* + size_t
处理字符串字面量(比如 "hello"_tag)时,重载函数签名必须是 operator""_tag(const char*, size_t),不是 const char* 单参数——后者只匹配字符字面量(如 'a'_tag)。
常见错误现象:写了 operator""_tag(const char*) 却对 "abc"_tag 报错,提示 no matching function。
立即学习“C++免费学习笔记(深入)”;
实操建议:
- 字符串字面量长度在编译期已知,
size_t参数就是它的长度(不含末尾\0) - 若想在编译期做验证(比如限制最大长度),得用
constexpr+if constexpr,但注意 C++17 起才支持constexpr字符串处理 - 别试图把
const char*直接转成std::string——这会强制运行期构造,失去字面量的零开销优势
数值字面量后缀分整型、浮点、用户定义三类
C++ 对数字字面量后缀做了严格分类:整数字面量走 unsigned long long 参数,浮点走 long double,而带小数点但无指数的(如 1.5)默认进浮点分支;15 和 15ULL 都走整型分支。
容易踩的坑:
-
operator""_m(15)和operator""_m(15.0)是两个完全不同的重载,必须分别定义 - 整型分支无法接收负数字面量(
-5_km解析为一元减号 +5_km),所以单位类通常只处理非负值,负号由外层运算处理 - 浮点分支用
long double是为了精度兼容性,但实际值可能被编译器截断——比如1.23456789012345678901234567890L在 x86-64 上仍是 80-bit 扩展精度,移植到 ARM 可能降为 64-bit
constexpr 自定义字面量不能依赖运行期数据
哪怕你把 operator""_km 声明为 constexpr,它内部也不能调用 std::sqrt、new 或访问全局变量——这些都会让整个表达式失去常量表达式资格。
典型场景:想写 auto d = 100_km + 200_m; 并期望结果是编译期计算出的 100200_m,那就必须保证所有中间转换(比如 km → m)都是纯 constexpr 算术。
实操建议:
- 优先用
constexpr整型算术(return value * 1000;),避免浮点运算或查表 - 若需类型安全(比如区分
distance和time),用空结构体 +constexpr构造函数封装,别用运行期static_assert - Clang/GCC 的
-Wconstexpr-not-const能帮你揪出隐式运行期依赖
最麻烦的其实是跨翻译单元的 constexpr 字面量——头文件里定义的 operator""_km 必须加 inline,否则链接时可能 ODR-violation。这点很容易被忽略,尤其在模板+字面量混用时。










