C++ 参考手册
- C++11
- C++14
- C++17
- C++20
- C++ 编译器支持情况表
- 独立与宿主实现
- C++ 语言
- 变量模板(C++14 起)
- 整数字面量
- 聚合初始化
- 比较运算符
- 默认比较(C++20 起)
- 转义序列
- for 循环
- while 循环
- 用户定义转换
- SFINAE
- 主函数
- ASCII 码表
- 标识符
- 类型
- 内存模型
- 对象
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 类
- 运算符重载
- 模板
- 异常
- 事务性内存
- 占位符类型说明符 (C++11 起)
- decltype 说明符
- 函数声明
- final 说明符 (C++11 起)
- override 说明符(C++11 起)
- 引用声明
- 移动构造函数
- 移动赋值运算符
- 枚举声明
- constexpr 说明符(C++11 起)
- 列表初始化 (C++11 起)
- 构造函数与成员初始化器列表
- using 声明
- nullptr,指针字面量
- 基础类型
- 类型别名,别名模版 (C++11 起)
- 形参包
- 联合体声明
- 字符串字面量
- 用户定义字面量 (C++11 起)
- 属性说明符序列(C++11 起)
- Lambda 表达式 (C++11 起)
- noexcept 说明符 (C++11 起)
- noexcept 运算符 (C++11 起)
- alignof 运算符(C++11 起)
- alignas 说明符 (C++11 起)
- 存储类说明符
- 基于范围的 for 循环 (C++11 起)
- static_assert 声明
- 隐式转换
- 代用运算符表示
- 自增/自减运算符
- 折叠表达式(C++17 起)
- 类模板实参推导(C++17 起)
- 模板形参与模板实参
- if 语句
- inline 说明符
- 结构化绑定声明 (C++17 起)
- switch 语句
- 字符字面量
- 命名空间
- 求值顺序
- 复制消除
- consteval 说明符 (C++20 起)
- constinit 说明符 (C++20 起)
- 协程 (C++20)
- 模块 (C++20 起)
- 约束与概念 (C++20 起)
- new 表达式
- do-while 循环
- continue 语句
- break 语句
- goto 语句
- return 语句
- 动态异常说明
- throw 表达式
- try 块
- 命名空间别名
- 类声明
- cv(const 与 volatile)类型限定符
- 默认初始化
- 值初始化(C++03 起)
- 零初始化
- 复制初始化
- 直接初始化
- 常量初始化
- 引用初始化
- 值类别
- C++ 运算符优先级
- 布尔字面量
- 浮点字面量
- typedef 说明符
- 显式类型转换
- static_cast 转换
- dynamic_cast 转换
- const_cast 转换
- reinterpret_cast 转换
- delete 表达式
- 构造函数与成员初始化器列表
- this 指针
- 访问说明符
- 友元声明
- virtual 函数说明符
- explicit 说明符
- 静态成员
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- 类模板
- 函数模板
- 显式(全)模板特化
- 汇编声明
- C++ 的历史
- 作用域
- 生存期
- 定义与单一定义规则(ODR)
- 名字查找
- 有限定的名字查找
- 无限定的名字查找
- 如同规则
- 未定义行为
- 翻译阶段
- 常量表达式
- 赋值运算符
- 算术运算符
- 逻辑运算符
- 成员访问运算符
- 其他运算符
- sizeof 运算符
- typeid 运算符
- 指针声明
- 数组声明
- 语言链接
- 详述类型说明符
- 默认实参
- 变长实参
- 实参依赖查找
- 重载决议
- 重载函数的地址
- 注入类名
- 非静态数据成员
- 非静态成员函数
- 嵌套类
- 派生类
- 空基类优化
- 抽象类
- 位域
- 转换构造函数
- 成员模板
- 模板实参推导
- 部分模板特化
- sizeof... 运算符
- 待决名
- 函数 try 块
- 扩充命名空间 std
- 字母缩写
- RAII
- 三/五/零之法则
- PImpl
- 零开销原则
- 类型
- 隐式转换
- 注释
- C++ 关键词
- 预处理器
- C++ 标准库头文件
- 具名要求
- 功能特性测试 (C++20)
- 工具库
- 类型支持(基本类型、RTTI、类型特性)
- 概念库 (C++20)
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 容器库
- 迭代器库
- 范围库 (C++20)
- 算法库
- 数值库
- 输入/输出库
- 文件系统库
- 本地化库
- 正则表达式库
- 原子操作库
- 线程支持库
- 实验性 C++ 特性
- 有用的资源
- 索引
- std 符号索引
- 协程支持 (C++20)
- C++ 关键词
用户定义字面量 (C++11 起)
通过定义用户定义的后缀,允许整数、浮点数、字符及字符串字面量产生用户定义类型的对象。
语法
用户定义字面量是下列形式的表达式之一
十进制字面量 ud-后缀 | (1) | ||||||||
八进制字面量 ud-后缀 | (2) | ||||||||
十六进制字面量 ud-后缀 | (3) | ||||||||
二进制字面量 ud-后缀 | (4) | ||||||||
分数常量 指数部分(可选) ud-后缀 | (5) | ||||||||
数字序列 指数部分 ud-后缀 | (6) | ||||||||
字符字面量 ud-后缀 | (7) | ||||||||
字符串字面量 ud-后缀 | (8) | ||||||||
十进制字面量 | - | 与整数字面量中相同,非零的十进制数位后随零或多个十进制数位 |
八进制字面量 | - | 与整数字面量中相同,零后随零或多个八进制数位 |
十六进制字面量 | - | 与整数字面量中相同,0x 或 0X 后随一个或多个十六进制数位
|
二进制字面量 | - | 与整数字面量中相同,0b 或 0B 后随一或多个二进制数位
|
数字序列 | - | 与浮点字面量中相同,一个十进制数字序列 |
分数常量 | - | 与浮点字面量中相同,要么是一个后随小数点的 字符序列(123.),要么是一个可选的 字符序列 后随小数点和另一个 字符序列(1.0 或 .12) |
指数部分 | - | 与浮点字面量中相同,字母 e 或字母 E 后随可选的正负号,后随 字符序列
|
字符字面量 | - | 与字符字面量中相同 |
字符串字面量 | - | 与字符串字面量中相同,包括原始字符串字面量 |
ud-后缀 | - | 标识符,由字面量运算符或字面量运算符模板声明引入(见下文)。所有程序引入的 ud-后缀 必须以下划线字符 _ 开始。标准库的 ud-后缀 不以下划线开始。
|
在整数和浮点字符序列中,允许在任何两个数位间插入可选的分隔符 |
(C++14 起) |
若一个记号同时匹配用户定义字面量的语法和常规字面量的语法,则它被假定为常规字面量(即不可能重载 123LL 中的 LL)
当编译器遇到一个带有 ud-后缀 X
的用户定义字面量时,它进行无限定名字查找,寻找名为 operator "" X
的函数。若找不到任何声明,则程序非良构。否则,
n
中的各个字符。f
是无 ud-后缀 的字面量f
中的各个字符。str
为无 ud-后缀 的字面量:
a) 若重载集包含带非类型模板形参的字符串字面量运算符模板,且 str 对它是良构的模板实参,则用户定义字面量表达式被当作函数调用 operator "" X<str>(),
|
(C++20 起) |
len
是字符串字面量的长度,不包含终止空字符ch
是无 ud-后缀 的字面量long double operator "" _w(long double); std::string operator "" _w(const char16_t*, size_t); unsigned operator "" _w(const char*); int main() { 1.2_w; // 调用运算符 "" _w(1.2L) u"one"_w; // 调用运算符 "" _w(u"one", 3) 12_w; // 调用运算符 "" _w("12") "two"_w; // 错误:无适用的字面量运算符 }
当在翻译阶段 6 中发生字符串字面量的拼接时,用户定义字符串字面量也被拼接,且其 ud-后缀 在拼接时被忽略,但所有被拼接的字面量中只可以出现一个后缀:
int main() { L"A" "B" "C"_x; // OK:同 L"ABC"_x "P"_x "Q" "R"_y;// 错误:二个不同的 ud-后缀(_x 与 _y) }
字面量运算符
用户定义字面量所调用的函数被称为字面量运算符(或若它是模板,则被称为字面量运算符模板)。它的声明恰如任何其他命名空间作用域的函数或函数模板一样(它可以是友元函数、函数模板的显式实例化或特化,或通过 using 声明引入),但有下列限制:
此函数的名称可拥有两种形式之一:
operator "" 标识符
|
|||||||||
operator 用户定义字符串字面量 (C++14 起)
|
|||||||||
标识符 | - | 作为用户定义字面量所用的 ud-后缀 的标识符,其将调用此函数。必须以下划线 _ 开始:不以下划线开始的后缀为标准库提供的字面量运算符所保留。
|
用户定义字符串字面量 | - | 字符序列 "" 后不带空格,后随将作为 ud-后缀 的字符序列。这种特殊语法使得将语言关键词和保留标识符用作 ud-后缀 成为可能,并由来自头文件 <complex> 的 operator ""if 的声明所用。注意,使用此形式不改变用户定义字面量必须以下划线开始的规则:类似 operator ""if 的声明只可出现作标准库头文及的一部分。然而,它允许下划线后随大写字母的用法(其他情况下这是保留标识符)。
|
若字面量运算符是模板,则它必须有空形参列表,而且只能有一个模板形参,模板形参必须是元素类型为 char 的非类型模板形参包(该情况下称之为数值字面量运算符模板)
template <char...> double operator "" _x();
或类类型的非类型模板形参(该情况下称之为字符串字面量运算符模板) struct A { A(const char *); auto operator<=>(const A&) const = default; }; template<A a> A operator ""_a(); |
(C++20 起) |
字面量运算符仅允许下列形参列表:
( const char * )
|
(1) | ||||||||
( unsigned long long int )
|
(2) | ||||||||
( long double )
|
(3) | ||||||||
( char )
|
(4) | ||||||||
( wchar_t )
|
(5) | ||||||||
( char8_t )
|
(6) | (C++20 起) | |||||||
( char16_t )
|
(7) | ||||||||
( char32_t )
|
(8) | ||||||||
( const char * , std::size_t )
|
(9) | ||||||||
( const wchar_t * , std::size_t )
|
(10) | ||||||||
( const char8_t * , std::size_t )
|
(11) | (C++20 起) | |||||||
( const char16_t * , std::size_t )
|
(12) | ||||||||
( const char32_t * , std::size_t )
|
(13) | ||||||||
不允许默认实参
不允许 C 语言连接
除了上述限制外,字面量运算符和字面量运算符模板都是普通的函数(和函数模板),它们可声明为 inline 或 constexpr,它们可拥有内部或外部连接,它们可显式调用,可取其地址,等等。
void operator "" _km(long double); // OK ,将为 1.0_km 所调用 std::string operator "" _i18n(const char*, std::size_t); // OK template <char...> double operator "" _π(); // OK float operator ""_e(const char*); // OK float operator ""Z(const char*); // 错误:后缀必须以下划线开始 double operator"" _Z(long double); // 错误:所有以下划线后随大写字母开始的名称受到保留 double operator""_Z(long double); // OK:虽然 _Z 被保留,但允许 ""_Z
注解
自从引入用户定义字面量之后,使用定宽整数类型格式化宏常量却不在前导字符串字面量后加空格变为非法:std::printf("%"PRId64"\n",INT64_MIN); 必须替换成 std::printf("%" PRId64"\n",INT64_MIN);
由于最大吞噬规则,以 p
、P
、 (C++17 起){tt|e}} 和 E
结束的用户定义整数和浮点字面量,在后随运算符 +
或 -
时,必须在源码中以空白符或括号与运算符分隔:
long double operator""_E(long double); long double operator""_a(long double); int operator""_p(unsigned long long); auto x = 1.0_E+2.0; // 错误 auto y = 1.0_a+2.0; // OK auto z = 1.0_E +2.0; // OK auto q = (1.0_E)+2.0; // OK auto w = 1_p+2; // 错误 auto u = 1_p +2; // OK
同样的规则适用于后随整数或浮点用户定义字面量的点运算符:
#include <chrono> using namespace std::literals; auto a = 4s.count(); // 错误 auto b = 4s .count(); // OK auto c = (4s).count(); // OK
否则会组成单个非法预处理数字记号(例如 1.0_E+2.0 或 4s.count),这导致编译失败。
示例
#include <iostream> // 用于转换 constexpr long double operator"" _deg ( long double deg ) { return deg * 3.14159265358979323846264L / 180; } // 用于自定义类型 struct mytype { unsigned long long m; }; constexpr mytype operator"" _mytype ( unsigned long long n ) { return mytype{n}; } // 用作副作用 void operator"" _print ( const char* str ) { std::cout << str; } int main(){ double x = 90.0_deg; std::cout << std::fixed << x << '\n'; mytype y = 123_mytype; std::cout << y.m << '\n'; 0x123ABC_print; }
输出:
1.570796 123 0x123ABC
标准库
标准库中定义了下列字面量运算符
定义于内联命名空间
std::literals::complex_literals | |
表示纯虚数的 std::complex 字面量 (函数) | |
定义于内联命名空间
std::literals::chrono_literals | |
(C++14) |
表示小时的 std::chrono::duration 字面量 (函数) |
(C++14) |
表示分钟的 std::chrono::duration 字面量 (函数) |
(C++14) |
表示秒的 std::chrono::duration 字面量 (函数) |
(C++14) |
表示毫秒的 std::chrono::duration 字面量 (函数) |
(C++14) |
表示微秒的 std::chrono::duration 字面量 (函数) |
(C++14) |
表示纳秒的 std::chrono::duration 字面量 (函数) |
(C++20) |
表示特定年的 std::chrono::year 字面量 (函数) |
(C++20) |
表示月内日期的 std::chrono::day 字面量 (函数) |
定义于内联命名空间
std::literals::string_literals | |
(C++14) |
转换字符数组字面量为 basic_string (函数) |
定义于内联命名空间
std::literals::string_view_literals | |
(C++17) |
创建一个字符数组字面量的字符串视图 (函数) |