用户定义字面量 (C++11 起)

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue 、右值 rvalue 、亡值 xvalue )
求值顺序(序列点)
常量表达式
不求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b
自增与自减++a, --a, a++, a--
算术运算符+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b
逻辑运算符a||b, a&&b, !a
比较运算符a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(C++20)
成员访问运算符a[b], *a, &a, a->b, a.b, a->*b, a.*b
其他运算符a(...), a,b, a?b:c
运算符的替代表示
优先级和结合性
折叠表达式(C++17)
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
运算符重载
类型转换
隐式转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)a, T(a)
用户定义转换
 

允许整数、浮点数、字符及字符串字面量通过用户定义的后缀产生用户定义类型的对象。

目录

[编辑] 语法

用户定义字面量是下列形式的表达式之一

decimal-literal ud-suffix (1)
octal-literal ud-suffix (2)
hex-literal ud-suffix (3)
binary-literal ud-suffix (4)
fractional-constant exponent-part(可选) ud-suffix (5)
digit-sequence exponent-part ud-suffix (6)
character-literal ud-suffix (7)
string-literal ud-suffix (8)
1-4) 用户定义整数字面量,例如 12_km
5-6) 用户定义浮点字面量,例如 0.5_Pa
7) 用户定义字符字面量,例如 'c'_X
8) 用户定义字符串字面量,例如 "abd"_Lu16"xyz"_M
decimal-literal - 同在整数字面量中,非零的十进制数位后随零或多个十进制数位
octal-literal - 同在整数字面量中,零后随零或多个八进制数位
hex-literal - 同在整数字面量中, 0x0X 后随一个或多个十六进制数位
binary-literal - 同在整数字面量中, 0b0B 后随一或多个二进制数位
digit-sequence - 同在浮点字面量中,一个十进制数字序列
fractional-constant - 同在浮点字面量中,要么是一个后随小数点的 digit-sequence123. ),要么是一个可选的 digit-sequence 后随小数点和另一个 digit-sequence1.0.12
exponent-part - 同在浮点字面量中,字母 e 或字母 E 后随可选的符号,后随 digit-sequence
character-literal - 同在字符字面量
string-literal - 同在字符串字面量中,含无修饰字符串字面量
ud-suffix - 标识符,由字面量运算符字面量运算符模板声明引入(见后述)。所有程序引入的 ud-suffix 必须以下划线字符 _ 开始。标准库的 ud-suffix 不以下划线开始。

在整数和浮点字符序列中,允许在二个数位间插入可选的分隔符 ' ,并忽略它们。

(C++14 起)

若记号匹配用户定义字面量和常规字面量语法,则它被假设为常规字面量(即不可能重载 123LL 中的 LL

当编译器用到带 ud-suffix X 的用户定义字面量时,它进行非限定名称查找,寻找名为 operator "" X 的函数。若找不到声明,则程序为病态。否则,

1) 对于用户定义字面量
a) 若重载集包含带参数类型 unsigned long long 的字面量运算符,则用户给定义字面量表达式被当做函数调用 operator "" X(nULL) ,其中 n 是无 ud-suffix 的字面量
b) 否则,重载集必须包含以下之一,但不是二者:无修饰字面量运算符或无修饰字面量运算符模板。若重载集包含无修饰字面量运算符,则用户定义字面量表达式被当做函数调用 operator "" X("n")
c) 否则,若重载集包含无修饰字面量运算符模板,则用户定义表达式被当做函数调用 operator "" X<'c1', 'c2', 'c3'..., 'ck'>() ,其中 c1..ck 是 n 的单个字符。
2) 对于用户定义浮点字面量,
a) 若重载集包含 long double 参数类型的字面量运算符,则用户定义字面量表达式被当做函数调用 operator "" X(fL) ,其中 f 是无 ud-suffix 的字面量
b) 否则,重载集必须包含下列之一,但不是二者:无修饰字面量运算符或无修饰字面量运算符模板。若重载集包含无修饰字面量运算符,则用户定义字面量表达式被当做函数调用 operator "" X("f")
c) 否则,若重载集包含无修饰字面量运算符模板,则用户定义表达式被当做函数调用 operator "" X<'c1', 'c2', 'c3'..., 'ck'>() ,其中 c1..ck 是 f 的单个字符
3) 对于用户定义字符串字面量,用户定义字面量表达式被处理成函数调用 operator "" X (str, len) ,其中 str 是无 ud-suffix 的字面量,且 len 是其排除空终止字符的长度
4) 对于用户定义字符字面量,用户定义字面量表达式被处理成函数调用 operator "" X (ch) ,其中 ch 是无 ud-suffix 的字面量
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-suffix 因连接的目的被忽略,除了所有被连接字面量只可以出现一个后缀:

int main() {
    L"A" "B" "C"_x; // OK :同 L"ABC"_x
    "P"_x "Q" "R"_y;// 错误:二个不同的 ud-suffix( _x 与 _y )
}

[编辑] 字面量运算符

用户定义字面量所调用的函数被称为字面量运算符(或若它是模板,则被称为字面量运算符模板)。它声明恰如任何其他在命名空间作用域的函数函数模板(它可以是友元函数、函数模板的显式实例化或特化,或通过 using 声明引入),除了下列限制:

此函数的名称可拥有二种形式之一:

operator "" identifier
operator user-defined-string-literal (C++14 起)
identifier - 将调用此函数的用户定义字面量所用的 ud-suffix 。必须以下划线 _ 开始:不以下划线开始的后缀为标准库提供的字面量运算符保留。
user-defined-string-literal - 字符序列 "" 后不带空格,跟随成为 ud-suffix 的字符序列。此特殊语法使得将语言关键词和保留标识符用作 ud-suffixes 可行,而且为来自头文件 <complex>operator ""if 的声明所用。注意使用此形式不改变用户定义字面量必须以下划线开始的规则:类似 operator ""if 的声明只可出现作标准库头文及的一部分。然而,它允许下划线后随大写字母的使用(在其他情况这是一个保留标识符)。

若字面量运算符是模板,则它必须拥有空参数列表且只能拥有一个模板参数,它必须是拥有元素类型 char 的非类型模板参数包

template <char...> double operator "" _x();

字面量运算符仅允许下列参数列表:

( const char * ) (1)
( unsigned long long int ) (2)
( long double ) (3)
( char ) (4)
( wchar_t ) (5)
( char16_t ) (6)
( char32_t ) (7)
( const char * , std::size_t ) (8)
( const wchar_t * , std::size_t ) (9)
( const char16_t * , std::size_t ) (10)
( const char32_t * , std::size_t ) (11)
1) 拥有此参数列表的字面量运算符是无修饰字面量运算符,用于整数和浮点用户定义字面量的回滚(见前述)
2) 拥有这些参数列表的字面量运算符是用户定义整数字面量的首选字面量运算符
3) 拥有这些参数列表的字面量运算符是用于定义浮点字面量的首选字面量运算符
4-7) 拥有这些参数列表的字面量运算符为用户定义的字符字面量所调用
8-11) 拥有这些参数列表的字面量运算符为用户定义的字符串字面量所调用

不允许默认参数

不允许 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);

由于最大吞噬规则,以 pP (C++17 起)eE 结束的用户定义整数和浮点字面量,在后随运算符 +- 时,必须在源码中以空白符或括号与运算符分隔:

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.04s.count ),这导致编译失败。

[编辑] 示例

#include <iostream>
 
// 用作转换
constexpr long double operator"" _deg ( long double deg )
{
    return deg*3.141592/180;
}
 
// 用于自定义类型
struct mytype
{
    mytype ( unsigned long long m):m(m){}
    unsigned long long m;
};
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
表示小时的 std::chrono::duration 字面量
(函数) [编辑]
表示分钟的 std::chrono::duration 字面量
(函数) [编辑]
表示秒的 std::chrono::duration 字面量
(函数) [编辑]
表示毫秒的 std::chrono::duration 字面量
(函数) [编辑]
表示微秒的 std::chrono::duration 字面量
(函数) [编辑]
表示纳秒的 std::chrono::duration 字面量
(函数) [编辑]
定义于内联命名空间 std::literals::string_literals
转换字符数组字面量为 basic_string
(函数) [编辑]
定义于内联命名空间 std::literals::string_view_literals
创建一个字符数组字面量的字符串视图
(函数) [编辑]